Merge pull request #18560 from edx/lduarte1991-annotations_deprecation
Lduarte1991 annotations deprecation
@@ -695,8 +695,7 @@ class MiscCourseTests(ContentStoreTestCase):
|
||||
# page response HTML
|
||||
self.check_components_on_page(
|
||||
ADVANCED_COMPONENT_TYPES,
|
||||
['Word cloud', 'Annotation', 'Text Annotation', 'Video Annotation', 'Image Annotation',
|
||||
'split_test'],
|
||||
['Word cloud', 'Annotation', 'split_test'],
|
||||
)
|
||||
|
||||
@ddt.data('/Fake/asset/displayname', '\\Fake\\asset\\displayname')
|
||||
|
||||
@@ -128,28 +128,7 @@
|
||||
'tooltip_manager': 'js/src/tooltip_manager',
|
||||
'draggabilly': 'js/vendor/draggabilly',
|
||||
'hls': 'common/js/vendor/hls',
|
||||
|
||||
// Files needed for Annotations feature
|
||||
'annotator': 'js/vendor/ova/annotator-full',
|
||||
'annotator-harvardx': 'js/vendor/ova/annotator-full-firebase-auth',
|
||||
'video.dev': 'js/vendor/ova/video.dev',
|
||||
'vjs.youtube': 'js/vendor/ova/vjs.youtube',
|
||||
'rangeslider': 'js/vendor/ova/rangeslider',
|
||||
'share-annotator': 'js/vendor/ova/share-annotator',
|
||||
'richText-annotator': 'js/vendor/ova/richText-annotator',
|
||||
'reply-annotator': 'js/vendor/ova/reply-annotator',
|
||||
'grouping-annotator': 'js/vendor/ova/grouping-annotator',
|
||||
'tags-annotator': 'js/vendor/ova/tags-annotator',
|
||||
'diacritic-annotator': 'js/vendor/ova/diacritic-annotator',
|
||||
'flagging-annotator': 'js/vendor/ova/flagging-annotator',
|
||||
'jquery-Watch': 'js/vendor/ova/jquery-Watch',
|
||||
'openseadragon': 'js/vendor/ova/openseadragon',
|
||||
'osda': 'js/vendor/ova/OpenSeaDragonAnnotation',
|
||||
'ova': 'js/vendor/ova/ova',
|
||||
'catch': 'js/vendor/ova/catch/js/catch',
|
||||
'handlebars': 'js/vendor/ova/catch/js/handlebars-1.1.2',
|
||||
'lang_edx': 'js/src/lang_edx',
|
||||
// end of Annotation tool files
|
||||
|
||||
// externally hosted files
|
||||
mathjax: '//cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // eslint-disable-line max-len
|
||||
|
||||
@@ -28,9 +28,6 @@ XMODULES = [
|
||||
"custom_tag_template = xmodule.raw_module:RawDescriptor",
|
||||
"about = xmodule.html_module:AboutDescriptor",
|
||||
"annotatable = xmodule.annotatable_module:AnnotatableDescriptor",
|
||||
"textannotation = xmodule.textannotation_module:TextAnnotationDescriptor",
|
||||
"videoannotation = xmodule.videoannotation_module:VideoAnnotationDescriptor",
|
||||
"imageannotation = xmodule.imageannotation_module:ImageAnnotationDescriptor",
|
||||
"word_cloud = xmodule.word_cloud_module:WordCloudDescriptor",
|
||||
"hidden = xmodule.hidden_module:HiddenDescriptor",
|
||||
"raw = xmodule.raw_module:RawDescriptor",
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
"""
|
||||
Module for Image annotations using annotator.
|
||||
"""
|
||||
import textwrap
|
||||
|
||||
from lxml import etree
|
||||
from pkg_resources import resource_string
|
||||
from web_fragments.fragment import Fragment
|
||||
from xblock.core import Scope, String
|
||||
|
||||
from xmodule.annotator_mixin import get_instructions, html_to_text
|
||||
from xmodule.annotator_token import retrieve_token
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
from xmodule.x_module import XModule
|
||||
|
||||
# Make '_' a no-op so we can scrape strings. Using lambda instead of
|
||||
# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file
|
||||
_ = lambda text: text
|
||||
|
||||
|
||||
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=_("The display name for this component."),
|
||||
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")
|
||||
)
|
||||
default_tab = String(
|
||||
display_name=_("Default Annotations Tab"),
|
||||
help=_("Select which tab will be the default in the annotations table: myNotes, Instructor, or Public."),
|
||||
scope=Scope.settings,
|
||||
default="myNotes",
|
||||
)
|
||||
# currently only supports one instructor, will build functionality for multiple later
|
||||
instructor_email = String(
|
||||
display_name=_("Email for 'Instructor' Annotations"),
|
||||
help=_("Email of the user that will be attached to all annotations that will be found in 'Instructor' tab."),
|
||||
scope=Scope.settings,
|
||||
default="",
|
||||
)
|
||||
annotation_mode = String(
|
||||
display_name=_("Mode for Annotation Tool"),
|
||||
help=_("Type in number corresponding to following modes: 'instructor' or 'everyone'"),
|
||||
scope=Scope.settings,
|
||||
default="everyone",
|
||||
)
|
||||
|
||||
|
||||
class ImageAnnotationModule(AnnotatableFields, XModule):
|
||||
'''Image Annotation Module'''
|
||||
js = {
|
||||
'js': [
|
||||
resource_string(__name__, 'js/src/html/display.js'),
|
||||
resource_string(__name__, 'js/src/annotatable/display.js'),
|
||||
resource_string(__name__, 'js/src/javascript_loader.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_email = ""
|
||||
self.is_course_staff = False
|
||||
if self.runtime.get_user_role() in ['instructor', 'staff']:
|
||||
self.is_course_staff = True
|
||||
if self.runtime.get_real_user is not None:
|
||||
try:
|
||||
self.user_email = self.runtime.get_real_user(self.runtime.anonymous_student_id).email
|
||||
except Exception: # pylint: disable=broad-except
|
||||
self.user_email = _("No email address found.")
|
||||
|
||||
def _extract_instructions(self, xmltree):
|
||||
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
|
||||
return get_instructions(xmltree)
|
||||
|
||||
def student_view(self, context):
|
||||
""" Renders parameters to template. """
|
||||
context = {
|
||||
'display_name': self.display_name_with_default_escaped,
|
||||
'instructions_html': self.instructions,
|
||||
'token': retrieve_token(self.user_email, self.annotation_token_secret),
|
||||
'tag': self.instructor_tags,
|
||||
'openseadragonjson': self.openseadragonjson,
|
||||
'annotation_storage': self.annotation_storage_url,
|
||||
'default_tab': self.default_tab,
|
||||
'instructor_email': self.instructor_email,
|
||||
'annotation_mode': self.annotation_mode,
|
||||
'is_course_staff': self.is_course_staff,
|
||||
}
|
||||
fragment = Fragment(self.system.render_template('imageannotation.html', context))
|
||||
|
||||
# TinyMCE already exists in Studio so we should not load the files again
|
||||
# get_real_user always returns "None" in Studio since its runtimes contains no anonymous ids
|
||||
if self.runtime.get_real_user is not None:
|
||||
fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
|
||||
fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
|
||||
return fragment
|
||||
|
||||
|
||||
class ImageAnnotationDescriptor(AnnotatableFields, RawDescriptor):
|
||||
''' Image annotation descriptor '''
|
||||
module_class = ImageAnnotationModule
|
||||
resources_dir = None
|
||||
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
|
||||
@@ -68,18 +68,6 @@ class InheritanceMixin(XBlockMixin):
|
||||
help=_("This setting is not currently supported."), scope=Scope.settings,
|
||||
deprecated=True
|
||||
)
|
||||
annotation_storage_url = String(
|
||||
help=_("Enter the location of the annotation storage server. The textannotation, videoannotation, and imageannotation advanced modules require this setting."),
|
||||
scope=Scope.settings,
|
||||
default="http://your_annotation_storage.com",
|
||||
display_name=_("URL for Annotation Storage")
|
||||
)
|
||||
annotation_token_secret = String(
|
||||
help=_("Enter the secret string for annotation storage. The textannotation, videoannotation, and imageannotation advanced modules require this string."),
|
||||
scope=Scope.settings,
|
||||
default="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
display_name=_("Secret Token String for Annotation")
|
||||
)
|
||||
graceperiod = Timedelta(
|
||||
help="Amount of time after the due date that submissions will be accepted",
|
||||
scope=Scope.settings,
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
# -*- 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>
|
||||
'''
|
||||
shard = 1
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Makes sure that the Module is declared and mocked with the sample xml above.
|
||||
"""
|
||||
super(ImageAnnotationModuleTestCase, self).setUp()
|
||||
|
||||
# return anything except None to test LMS
|
||||
def test_real_user(useless):
|
||||
useless_user = Mock(email='fake@fake.com', id=useless)
|
||||
return useless_user
|
||||
|
||||
# test to make sure that role is checked in LMS
|
||||
def test_user_role():
|
||||
return 'staff'
|
||||
|
||||
self.system = get_test_system()
|
||||
self.system.get_real_user = test_real_user
|
||||
self.system.get_user_role = test_user_role
|
||||
self.system.anonymous_student_id = None
|
||||
|
||||
self.mod = ImageAnnotationModule(
|
||||
Mock(),
|
||||
self.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_student_view(self):
|
||||
"""
|
||||
Tests the function that passes in all the information in the context
|
||||
that will be used in templates/imageannotation.html
|
||||
"""
|
||||
context = self.mod.student_view({}).content
|
||||
|
||||
for key in ['display_name',
|
||||
'instructions_html',
|
||||
'annotation_storage',
|
||||
'token',
|
||||
'tag',
|
||||
'openseadragonjson',
|
||||
'default_tab',
|
||||
'instructor_email',
|
||||
'annotation_mode',
|
||||
'is_course_staff']:
|
||||
self.assertIn(key, context)
|
||||
@@ -1,91 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"Test for 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.textannotation_module import TextAnnotationModule
|
||||
|
||||
from . import get_test_system
|
||||
|
||||
|
||||
class TextAnnotationModuleTestCase(unittest.TestCase):
|
||||
''' text Annotation Module Test Case '''
|
||||
sample_xml = '''
|
||||
<annotatable>
|
||||
<instructions><p>Test Instructions.</p></instructions>
|
||||
<p>
|
||||
One Fish. Two Fish.
|
||||
Red Fish. Blue Fish.
|
||||
|
||||
Oh the places you'll go!
|
||||
</p>
|
||||
</annotatable>
|
||||
'''
|
||||
shard = 1
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Makes sure that the Module is declared and mocked with the sample xml above.
|
||||
"""
|
||||
super(TextAnnotationModuleTestCase, self).setUp()
|
||||
|
||||
# return anything except None to test LMS
|
||||
def test_real_user(useless):
|
||||
useless_user = Mock(email='fake@fake.com', id=useless)
|
||||
return useless_user
|
||||
|
||||
# test to make sure that role is checked in LMS
|
||||
def test_user_role():
|
||||
return 'staff'
|
||||
|
||||
self.system = get_test_system()
|
||||
self.system.get_real_user = test_real_user
|
||||
self.system.get_user_role = test_user_role
|
||||
self.system.anonymous_student_id = None
|
||||
|
||||
self.mod = TextAnnotationModule(
|
||||
Mock(),
|
||||
self.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>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_student_view(self):
|
||||
"""
|
||||
Tests the function that passes in all the information in the context
|
||||
that will be used in templates/textannotation.html
|
||||
"""
|
||||
context = self.mod.student_view({}).content
|
||||
for key in ['display_name',
|
||||
'tag',
|
||||
'source',
|
||||
'instructions_html',
|
||||
'content_html',
|
||||
'annotation_storage',
|
||||
'token',
|
||||
'diacritic_marks',
|
||||
'default_tab',
|
||||
'annotation_mode',
|
||||
'is_course_staff']:
|
||||
self.assertIn(key, context)
|
||||
@@ -1,97 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"Test for 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.videoannotation_module import VideoAnnotationModule
|
||||
|
||||
from . import get_test_system
|
||||
|
||||
|
||||
class VideoAnnotationModuleTestCase(unittest.TestCase):
|
||||
''' Video Annotation Module Test Case '''
|
||||
sample_xml = '''
|
||||
<annotatable>
|
||||
<instructions><p>Video Test Instructions.</p></instructions>
|
||||
</annotatable>
|
||||
'''
|
||||
shard = 1
|
||||
sample_sourceurl = "http://video-js.zencoder.com/oceans-clip.mp4"
|
||||
sample_youtubeurl = "http://www.youtube.com/watch?v=yxLIu-scR9Y"
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Makes sure that the Video Annotation Module is created.
|
||||
"""
|
||||
super(VideoAnnotationModuleTestCase, self).setUp()
|
||||
|
||||
# return anything except None to test LMS
|
||||
def test_real_user(useless):
|
||||
useless_user = Mock(email='fake@fake.com', id=useless)
|
||||
return useless_user
|
||||
|
||||
# test to make sure that role is checked in LMS
|
||||
def test_user_role():
|
||||
return 'staff'
|
||||
|
||||
self.system = get_test_system()
|
||||
self.system.get_real_user = test_real_user
|
||||
self.system.get_user_role = test_user_role
|
||||
self.system.anonymous_student_id = None
|
||||
|
||||
self.mod = VideoAnnotationModule(
|
||||
Mock(),
|
||||
self.system,
|
||||
DictFieldData({'data': self.sample_xml, 'sourceUrl': self.sample_sourceurl}),
|
||||
ScopeIds(None, None, None, None)
|
||||
)
|
||||
|
||||
def test_extract_instructions(self):
|
||||
"""
|
||||
This test ensures that if an instruction exists it is pulled and
|
||||
formatted from the <instructions> tags. Otherwise, it should return nothing.
|
||||
"""
|
||||
xmltree = etree.fromstring(self.sample_xml)
|
||||
|
||||
expected_xml = u"<div><p>Video 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_extension(self):
|
||||
"""
|
||||
Tests the function that returns the appropriate extension depending on whether it is
|
||||
a video from youtube, or one uploaded to the EdX server.
|
||||
"""
|
||||
expectedyoutube = 'video/youtube'
|
||||
expectednotyoutube = 'video/mp4'
|
||||
result1 = self.mod._get_extension(self.sample_sourceurl) # pylint: disable=protected-access
|
||||
result2 = self.mod._get_extension(self.sample_youtubeurl) # pylint: disable=protected-access
|
||||
self.assertEqual(expectedyoutube, result2)
|
||||
self.assertEqual(expectednotyoutube, result1)
|
||||
|
||||
def test_student_view(self):
|
||||
"""
|
||||
Tests to make sure variables passed in truly exist within the html once it is all rendered.
|
||||
"""
|
||||
context = self.mod.student_view({}).content
|
||||
for key in ['display_name',
|
||||
'instructions_html',
|
||||
'sourceUrl',
|
||||
'typeSource',
|
||||
'poster',
|
||||
'annotation_storage',
|
||||
'default_tab',
|
||||
'instructor_email',
|
||||
'annotation_mode',
|
||||
'is_course_staff']:
|
||||
self.assertIn(key, context)
|
||||
@@ -1,160 +0,0 @@
|
||||
"""Text annotation module"""
|
||||
import textwrap
|
||||
|
||||
from lxml import etree
|
||||
from pkg_resources import resource_string
|
||||
from web_fragments.fragment import Fragment
|
||||
from xblock.core import Scope, String
|
||||
|
||||
from xmodule.annotator_mixin import get_instructions
|
||||
from xmodule.annotator_token import retrieve_token
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
from xmodule.x_module import XModule
|
||||
|
||||
# Make '_' a no-op so we can scrape strings. Using lambda instead of
|
||||
# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file
|
||||
_ = lambda text: text
|
||||
|
||||
|
||||
class AnnotatableFields(object):
|
||||
"""Fields for `TextModule` and `TextDescriptor`."""
|
||||
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>
|
||||
</annotatable>
|
||||
"""))
|
||||
display_name = String(
|
||||
display_name=_("Display Name"),
|
||||
help=_("The display name for this component."),
|
||||
scope=Scope.settings,
|
||||
default=_('Text 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='imagery:red,parallelism:blue',
|
||||
)
|
||||
source = String(
|
||||
display_name=_("Source/Citation"),
|
||||
help=_("Optional for citing source of any material used. Automatic citation can be done using <a href=\"http://easybib.com\">EasyBib</a>"),
|
||||
scope=Scope.settings,
|
||||
default='None',
|
||||
)
|
||||
diacritics = String(
|
||||
display_name=_("Diacritic Marks"),
|
||||
help=_("Add diacritic marks to be added to a text using the comma-separated form, i.e. markname;urltomark;baseline,markname2;urltomark2;baseline2"),
|
||||
scope=Scope.settings,
|
||||
default='',
|
||||
)
|
||||
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")
|
||||
)
|
||||
default_tab = String(
|
||||
display_name=_("Default Annotations Tab"),
|
||||
help=_("Select which tab will be the default in the annotations table: myNotes, Instructor, or Public."),
|
||||
scope=Scope.settings,
|
||||
default="myNotes",
|
||||
)
|
||||
# currently only supports one instructor, will build functionality for multiple later
|
||||
instructor_email = String(
|
||||
display_name=_("Email for 'Instructor' Annotations"),
|
||||
help=_("Email of the user that will be attached to all annotations that will be found in 'Instructor' tab."),
|
||||
scope=Scope.settings,
|
||||
default="",
|
||||
)
|
||||
annotation_mode = String(
|
||||
display_name=_("Mode for Annotation Tool"),
|
||||
help=_("Type in number corresponding to following modes: 'instructor' or 'everyone'"),
|
||||
scope=Scope.settings,
|
||||
default="everyone",
|
||||
)
|
||||
|
||||
|
||||
class TextAnnotationModule(AnnotatableFields, XModule):
|
||||
''' Text Annotation Module '''
|
||||
js = {'js': []}
|
||||
css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]}
|
||||
icon_class = 'textannotation'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TextAnnotationModule, self).__init__(*args, **kwargs)
|
||||
|
||||
xmltree = etree.fromstring(self.data)
|
||||
|
||||
self.instructions = self._extract_instructions(xmltree)
|
||||
self.content = etree.tostring(xmltree, encoding='unicode')
|
||||
self.user_email = ""
|
||||
self.is_course_staff = False
|
||||
if self.runtime.get_user_role() in ['instructor', 'staff']:
|
||||
self.is_course_staff = True
|
||||
if self.runtime.get_real_user is not None:
|
||||
try:
|
||||
self.user_email = self.runtime.get_real_user(self.runtime.anonymous_student_id).email
|
||||
except Exception: # pylint: disable=broad-except
|
||||
self.user_email = _("No email address found.")
|
||||
|
||||
def _extract_instructions(self, xmltree):
|
||||
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
|
||||
return get_instructions(xmltree)
|
||||
|
||||
def student_view(self, context):
|
||||
""" Renders parameters to template. """
|
||||
context = {
|
||||
'course_key': self.runtime.course_id,
|
||||
'display_name': self.display_name_with_default_escaped,
|
||||
'tag': self.instructor_tags,
|
||||
'source': self.source,
|
||||
'instructions_html': self.instructions,
|
||||
'content_html': self.content,
|
||||
'token': retrieve_token(self.user_email, self.annotation_token_secret),
|
||||
'diacritic_marks': self.diacritics,
|
||||
'annotation_storage': self.annotation_storage_url,
|
||||
'default_tab': self.default_tab,
|
||||
'instructor_email': self.instructor_email,
|
||||
'annotation_mode': self.annotation_mode,
|
||||
'is_course_staff': self.is_course_staff,
|
||||
}
|
||||
fragment = Fragment(self.system.render_template('textannotation.html', context))
|
||||
|
||||
# TinyMCE already exists in Studio so we should not load the files again
|
||||
# get_real_user always returns "None" in Studio since its runtimes contains no anonymous ids
|
||||
if self.runtime.get_real_user is not None:
|
||||
fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
|
||||
fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
|
||||
return fragment
|
||||
|
||||
|
||||
class TextAnnotationDescriptor(AnnotatableFields, RawDescriptor):
|
||||
''' Text Annotation Descriptor '''
|
||||
module_class = TextAnnotationModule
|
||||
resources_dir = None
|
||||
mako_template = "widgets/raw-edit.html"
|
||||
|
||||
@property
|
||||
def non_editable_metadata_fields(self):
|
||||
non_editable_fields = super(TextAnnotationDescriptor, self).non_editable_metadata_fields
|
||||
non_editable_fields.extend([
|
||||
TextAnnotationDescriptor.annotation_storage_url,
|
||||
TextAnnotationDescriptor.annotation_token_secret,
|
||||
])
|
||||
return non_editable_fields
|
||||
@@ -1,165 +0,0 @@
|
||||
"""
|
||||
Module for Video annotations using annotator.
|
||||
"""
|
||||
import textwrap
|
||||
|
||||
from lxml import etree
|
||||
from pkg_resources import resource_string
|
||||
from web_fragments.fragment import Fragment
|
||||
from xblock.core import Scope, String
|
||||
|
||||
from xmodule.annotator_mixin import get_extension, get_instructions
|
||||
from xmodule.annotator_token import retrieve_token
|
||||
from xmodule.raw_module import RawDescriptor
|
||||
from xmodule.x_module import XModule
|
||||
|
||||
# Make '_' a no-op so we can scrape strings. Using lambda instead of
|
||||
# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file
|
||||
_ = lambda text: text
|
||||
|
||||
|
||||
class AnnotatableFields(object):
|
||||
""" Fields for `VideoModule` and `VideoDescriptor`. """
|
||||
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>
|
||||
</annotatable>
|
||||
"""))
|
||||
display_name = String(
|
||||
display_name=_("Display Name"),
|
||||
help=_("The display name for this component."),
|
||||
scope=Scope.settings,
|
||||
default=_('Video Annotation'),
|
||||
)
|
||||
sourceurl = String(
|
||||
help=_("The external source URL for the video."),
|
||||
display_name=_("Source URL"),
|
||||
scope=Scope.settings, default="http://video-js.zencoder.com/oceans-clip.mp4"
|
||||
)
|
||||
poster_url = String(
|
||||
help=_("Poster Image URL"),
|
||||
display_name=_("Poster URL"),
|
||||
scope=Scope.settings,
|
||||
default=""
|
||||
)
|
||||
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")
|
||||
)
|
||||
default_tab = String(
|
||||
display_name=_("Default Annotations Tab"),
|
||||
help=_("Select which tab will be the default in the annotations table: myNotes, Instructor, or Public."),
|
||||
scope=Scope.settings,
|
||||
default="myNotes",
|
||||
)
|
||||
# currently only supports one instructor, will build functionality for multiple later
|
||||
instructor_email = String(
|
||||
display_name=_("Email for 'Instructor' Annotations"),
|
||||
help=_("Email of the user that will be attached to all annotations that will be found in 'Instructor' tab."),
|
||||
scope=Scope.settings,
|
||||
default="",
|
||||
)
|
||||
annotation_mode = String(
|
||||
display_name=_("Mode for Annotation Tool"),
|
||||
help=_("Type in number corresponding to following modes: 'instructor' or 'everyone'"),
|
||||
scope=Scope.settings,
|
||||
default="everyone",
|
||||
)
|
||||
|
||||
|
||||
class VideoAnnotationModule(AnnotatableFields, XModule):
|
||||
'''Video Annotation Module'''
|
||||
js = {
|
||||
'js': [
|
||||
resource_string(__name__, 'js/src/html/display.js'),
|
||||
resource_string(__name__, 'js/src/annotatable/display.js'),
|
||||
resource_string(__name__, 'js/src/javascript_loader.js'),
|
||||
resource_string(__name__, 'js/src/collapsible.js'),
|
||||
]
|
||||
}
|
||||
css = {'scss': [resource_string(__name__, 'css/annotatable/display.scss')]}
|
||||
icon_class = 'videoannotation'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(VideoAnnotationModule, self).__init__(*args, **kwargs)
|
||||
|
||||
xmltree = etree.fromstring(self.data)
|
||||
|
||||
self.instructions = self._extract_instructions(xmltree)
|
||||
self.content = etree.tostring(xmltree, encoding='unicode')
|
||||
self.user_email = ""
|
||||
self.is_course_staff = False
|
||||
if self.runtime.get_user_role() in ['instructor', 'staff']:
|
||||
self.is_course_staff = True
|
||||
if self.runtime.get_real_user is not None:
|
||||
try:
|
||||
self.user_email = self.runtime.get_real_user(self.runtime.anonymous_student_id).email
|
||||
except Exception: # pylint: disable=broad-except
|
||||
self.user_email = _("No email address found.")
|
||||
|
||||
def _extract_instructions(self, xmltree):
|
||||
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
|
||||
return get_instructions(xmltree)
|
||||
|
||||
def _get_extension(self, src_url):
|
||||
''' get the extension of a given url '''
|
||||
return get_extension(src_url)
|
||||
|
||||
def student_view(self, context):
|
||||
""" Renders parameters to template. """
|
||||
extension = self._get_extension(self.sourceurl)
|
||||
|
||||
context = {
|
||||
'course_key': self.runtime.course_id,
|
||||
'display_name': self.display_name_with_default_escaped,
|
||||
'instructions_html': self.instructions,
|
||||
'sourceUrl': self.sourceurl,
|
||||
'typeSource': extension,
|
||||
'poster': self.poster_url,
|
||||
'content_html': self.content,
|
||||
'token': retrieve_token(self.user_email, self.annotation_token_secret),
|
||||
'annotation_storage': self.annotation_storage_url,
|
||||
'default_tab': self.default_tab,
|
||||
'instructor_email': self.instructor_email,
|
||||
'annotation_mode': self.annotation_mode,
|
||||
'is_course_staff': self.is_course_staff,
|
||||
}
|
||||
fragment = Fragment(self.system.render_template('videoannotation.html', context))
|
||||
|
||||
# TinyMCE already exists in Studio so we should not load the files again
|
||||
# get_real_user always returns "None" in Studio since its runtimes contains no anonymous ids
|
||||
if self.runtime.get_real_user is not None:
|
||||
fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/tinymce.full.min.js")
|
||||
fragment.add_javascript_url(self.runtime.STATIC_URL + "js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js")
|
||||
return fragment
|
||||
|
||||
|
||||
class VideoAnnotationDescriptor(AnnotatableFields, RawDescriptor):
|
||||
''' Video annotation descriptor '''
|
||||
module_class = VideoAnnotationModule
|
||||
resources_dir = None
|
||||
mako_template = "widgets/raw-edit.html"
|
||||
|
||||
@property
|
||||
def non_editable_metadata_fields(self):
|
||||
non_editable_fields = super(VideoAnnotationDescriptor, self).non_editable_metadata_fields
|
||||
non_editable_fields.extend([
|
||||
VideoAnnotationDescriptor.annotation_storage_url,
|
||||
VideoAnnotationDescriptor.annotation_token_secret,
|
||||
])
|
||||
return non_editable_fields
|
||||
888
common/static/css/vendor/ova/annotator.css
vendored
@@ -1,8 +0,0 @@
|
||||
.mark{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: absolute;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 0%;
|
||||
}
|
||||
108
common/static/css/vendor/ova/edx-annotator.css
vendored
@@ -1,108 +0,0 @@
|
||||
/*This is written to fix some design problems with edX*/
|
||||
.annotatable-wrapper .annotatable-header .annotatable-title{
|
||||
padding-top: 20px !important;
|
||||
}
|
||||
|
||||
.annotator-wrapper .annotator-adder button {
|
||||
opacity:0;
|
||||
}
|
||||
.annotator-editor a, .annotator-filter .annotator-filter-property label{
|
||||
line-height: 24px !important;
|
||||
color: #363636 !important;
|
||||
font-size: 12px!important;
|
||||
font-weight: bold !important;
|
||||
text-shadow: none !important;
|
||||
}
|
||||
.annotator-outer ul {
|
||||
list-style: none !important;
|
||||
padding-left: 0em !important;
|
||||
}
|
||||
.annotator-outer li {
|
||||
margin-bottom: 0em!important;
|
||||
}
|
||||
.vjs-rangeslider-holder span.vjs-time-text{
|
||||
line-height: 1!important;
|
||||
float: left;
|
||||
}
|
||||
span.annotator-hl{
|
||||
font:inherit;
|
||||
}
|
||||
.vjs-has-started .vjs-loading-spinner {
|
||||
display: none!important;
|
||||
}
|
||||
/*Catch*/
|
||||
#mainCatch *{
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/*PublicPrivate Notes in My notes */
|
||||
.notes-wrapper .PublicPrivate.separator,
|
||||
.notes-wrapper .PublicPrivate.myNotes{
|
||||
position:relative;
|
||||
float:left;
|
||||
}
|
||||
.notes-wrapper .PublicPrivate.active *{
|
||||
color:black;
|
||||
}
|
||||
|
||||
/* My notes buttons */
|
||||
.notes-wrapper .buttonCatch{
|
||||
-moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
-webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
|
||||
background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ffffff), color-stop(1, #a6a3a3));
|
||||
background:-moz-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:-webkit-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:-o-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:-ms-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:linear-gradient(to bottom, #ffffff 5%, #a6a3a3 100%);
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#a6a3a3',GradientType=0);
|
||||
|
||||
background-color:#ffffff;
|
||||
|
||||
-moz-border-radius:6px;
|
||||
-webkit-border-radius:6px;
|
||||
border-radius:6px;
|
||||
|
||||
border:1px solid #c2c2c2;
|
||||
|
||||
display:inline-block;
|
||||
color:#302f2f;
|
||||
font-family:arial;
|
||||
font-size:15px;
|
||||
font-weight:bold;
|
||||
padding:6px 24px;
|
||||
text-decoration:none;
|
||||
|
||||
text-shadow:0px 1px 0px #ffffff;
|
||||
margin: 0px 5px 10px 5px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.notes-wrapper .buttonCatch.active{
|
||||
color:red;
|
||||
}
|
||||
.notes-wrapper .buttonCatch:hover {
|
||||
background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #a6a3a3), color-stop(1, #ffffff));
|
||||
background:-moz-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:-webkit-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:-o-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:-ms-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:linear-gradient(to bottom, #a6a3a3 5%, #ffffff 100%);
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#a6a3a3', endColorstr='#ffffff',GradientType=0);
|
||||
|
||||
background-color:#a6a3a3;
|
||||
}
|
||||
.notes-wrapper .buttonCatch:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
|
||||
.annotatable-content #sourceCitation {
|
||||
color:#CCC;
|
||||
font-style:italic;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
.flag-icon{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAsCAMAAAAgsQpJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAytpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDQ1NzExMTM2MEUwMTFFM0I2RjhDOENEOEZGRUY1MzQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDQ1NzExMTI2MEUwMTFFM0I2RjhDOENEOEZGRUY1MzQiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5kaWQ6YWNmNmE5ZGQtZDlkOC00YTlhLThmMjAtY2EzNGM5ODcxZDJhIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOmFjZjZhOWRkLWQ5ZDgtNGE5YS04ZjIwLWNhMzRjOTg3MWQyYSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pnen528AAAAJUExURc3Nzf///////3aZ7dEAAAADdFJOU///ANfKDUEAAACzSURBVHjarNRLFoJADETRZ+1/0cpAYuevx8w4XOjQdApZ8SpVxQ+QJYRW4hzV+3GO4rk3hFNCWMG765a7NEhbBtlBxtK86peQNbws/y+teoz/ofiWFbSTtHLTHt0TErddqfMHNxxGWzUbj8SlUIdL5trBc9Br6AKh7PHh5pXc1XM9uQiT9lJYOQc//mGXj51LgrTIPpbOBWmTuizaC/moOZr79k44uDtIJ3cmriao2ekpwADT/geMPTQb1AAAAABJRU5ErkJggg==");
|
||||
background-repeat: no-repeat;
|
||||
background-size:13px 13px;
|
||||
top: 2px;
|
||||
left: 5px;
|
||||
float: left;
|
||||
border: none;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.flag-icon-used, .flag-icon:hover{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAsCAMAAAAgsQpJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAytpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDQ1NzExMEY2MEUwMTFFM0I2RjhDOENEOEZGRUY1MzQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDQ1NzExMEU2MEUwMTFFM0I2RjhDOENEOEZGRUY1MzQiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5kaWQ6YWNmNmE5ZGQtZDlkOC00YTlhLThmMjAtY2EzNGM5ODcxZDJhIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOmFjZjZhOWRkLWQ5ZDgtNGE5YS04ZjIwLWNhMzRjOTg3MWQyYSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PpBey0IAAAAVUExURQAAAAEBAQ4ODrGxscHBwfj4+P///6napTIAAAAHdFJOU////////wAaSwNGAAABW0lEQVR42oyVWQLDIAhEBwZy/yNX3EpSo+WrSV+GVcT1NVf1682Qfquq/QNSAP4BEhC8+56gAUFOSVKVC9BUg4Sm7zQnh5GwVMWhwngQTR4w9KSRUkWIZuWlZZBNr5NKxbTpHcPP/Cscfp8gHKAT2URE8iO6c7jiYK0QUNlj0vuKu6c1auZFEUdOQ/UcY3FZuqm4eOKiO0Xtug4x1qaG4l6ydsZYwS1ZueLde6+TguXs2CafY3p8TI/SyyjN0rL5szy4LEPD1lZNaRjRO7M4HtbaGkCpcp+zFRiSZS4tPpkjvgTjYATHOY2vIOTBLcFyMki32yFcgZQQ8ju3AFnLZxIl3YFtU9nPGsIv56H6s9fwKHVwkbTv9mMPrNC07SJtgcXcHxZp4wDbL1KNBOKo2XaRek/jdd8jcy/h3fcjH0OwBqsSd5dCAy247S3TwYhQd9dWjnHVjWwfAQYAR+4aJLhjvXgAAAAASUVORK5CYII=");
|
||||
background-repeat: no-repeat;
|
||||
background-size:13px 13px;
|
||||
top: 2px;
|
||||
left: 5px;
|
||||
float: left;
|
||||
border: none;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
.groupButton {
|
||||
background-color: rgba(255, 255, 10, 0.3);
|
||||
position: absolute;
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
right: -17px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
padding: 2px;
|
||||
border: 1px solid black;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.groupButton:hover {
|
||||
width: 60px;
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.onOffGroupButton, .onOffGroupButton.buttonOn {
|
||||
border: 1px solid blue;
|
||||
background-color: rgba(255, 255, 10, 0.3);
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
color: black;
|
||||
position: relative;
|
||||
margin-left: auto;
|
||||
margin-bottom: 10px;
|
||||
width: 220px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.onOffGroupButton.buttonOff {
|
||||
border: 1px solid black;
|
||||
background-color: rgba(8, 8, 8, 0.3);
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
color: black;
|
||||
position: relative;
|
||||
margin-left: auto;
|
||||
margin-bottom: 10px;
|
||||
width: 220px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
605
common/static/css/vendor/ova/ova.css
vendored
@@ -1,605 +0,0 @@
|
||||
/* --- BigNewAnnotation --- */
|
||||
|
||||
.vjs-default-skin .vjs-big-new-annotation{
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
line-height: 1.6em;
|
||||
margin: 3% 3% 3% 4%;
|
||||
top: 41%;
|
||||
width: 6em;
|
||||
height: 6em;
|
||||
background-color: rgba(7,40,50,.7);
|
||||
border-radius: 6px;
|
||||
border: 0.25em solid #ccc;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-big-new-annotation div{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0em;
|
||||
font-weight: bold;
|
||||
font-size: 600%;
|
||||
padding-top: 0.32em;
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-fullscreen .vjs-big-new-annotation{
|
||||
top: 68%;
|
||||
width: 8em;
|
||||
height: 8em;
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-fullscreen .vjs-big-new-annotation div{
|
||||
font-size: 750%;
|
||||
padding-top: 42%;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-big-new-annotation div:hover {
|
||||
-webkit-box-shadow: 0 0 1em rgba(255, 255, 255, 1);
|
||||
-moz-box-shadow: 0 0 1em rgba(255, 255, 255, 1);
|
||||
box-shadow: 0 0 1em rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
div.video-js > div.vjs-big-new-annotation {
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
-webkit-transition: visibility 0s linear 1s,opacity 1s linear;
|
||||
-moz-transition: visibility 0s linear 1s,opacity 1s linear;
|
||||
-o-transition: visibility 0s linear 1s,opacity 1s linear;
|
||||
transition:visibility 0s linear 1s,opacity 1s linear;
|
||||
}
|
||||
div.video-js:hover > div.vjs-big-new-annotation {
|
||||
visibility:visible;
|
||||
opacity:1;
|
||||
transition-delay:0s;
|
||||
}
|
||||
|
||||
|
||||
.vjs-default-skin .vjs-big-new-annotation.ul{
|
||||
top:0%;
|
||||
}
|
||||
.vjs-default-skin .vjs-big-new-annotation.ur{
|
||||
top:0%;
|
||||
float:right;
|
||||
}
|
||||
.vjs-default-skin .vjs-big-new-annotation.br{
|
||||
float:right;
|
||||
}
|
||||
.vjs-default-skin .vjs-big-new-annotation.c{
|
||||
top:24%;
|
||||
left:40%;
|
||||
}
|
||||
|
||||
div.video-js:hover > div.vjs-big-new-annotation.none {
|
||||
visibility:hidden;
|
||||
}
|
||||
.vjs-default-skin.vjs-fullscreen .vjs-big-new-annotation.c{
|
||||
top:35%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> AnContainerButtons --- */
|
||||
|
||||
.vjs-default-skin .vjs-container-button-annotation{
|
||||
width: 101px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> AnContainerButtons --> ShowStatistics --- */
|
||||
/* --- ControlBar --> AnContainerButtons --> NewAnnotation --- */
|
||||
/* --- ControlBar --> AnContainerButtons --> ShowAnnotations --- */
|
||||
|
||||
.vjs-default-skin .vjs-statistics-annotation,
|
||||
.vjs-default-skin .vjs-showannotations-annotation,
|
||||
.vjs-default-skin .vjs-new-annotation{
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
line-height: 1.6em;
|
||||
background-position: left top;
|
||||
margin: 4px;
|
||||
width: 23px;
|
||||
height: 21px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-statistics-annotation.active,
|
||||
.vjs-default-skin .vjs-showannotations-annotation.active,
|
||||
.vjs-default-skin .vjs-statistics-annotation:hover,
|
||||
.vjs-default-skin .vjs-showannotations-annotation:hover,
|
||||
.vjs-default-skin .vjs-new-annotation:hover {
|
||||
background-position: center top;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-statistics-annotation:active,
|
||||
.vjs-default-skin .vjs-showannotations-annotation:active,
|
||||
.vjs-default-skin .vjs-new-annotation:active {
|
||||
background-position: center right;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-new-annotation {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEUAAAAVCAYAAAAQAyPeAAAABmJLR0QA/wDoAACU1v3rAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QgdAg4VAK182QAACfBJREFUWMOtmHtwVNUdxz/n3LubF4tAMAYEIYC8UiGOaAvYlwUqSqO042MQZgRsZ5R2pr5QW6d2FGEc6VhqLdQiDHQKRpniFBUd0JHUimSAmFB5CAQkD8mDJLvZ5733nNM/drMPgmgNZ+Y32fnt/r4553t+zyMAXlyzZuTw4cPXBwKBOVJKvukyxhCJRo81NzUteGnt2rrDhw+r6ZUvjLy8ZPj6/ILAbIEQ3xgbg5OIHmtrbV5Qv2ddXbj7iLo3f+bIsitGrx9cPGS2FPKbYQswRhMKho6dbD25YEe0vk48t2rV5ZMmT66fNXt2qVYKbQz9Wfn5eRw8cNDZu3fvjM3vRM6MLptcf911N5eG435UP6AFECgyNJ6qcQ7V750xdMcrZ26cPLP+/p/fX5rfbRD9ADcSKM5j+/tvOjvf3TnDHjx48NqpFVNL4/E4l2L19LiMnzDBf6qhYduAQNeBsVdPK+3o8YPpP3ZHl6D4iqn+gYNObbuycNiBW+fcUpp31sVg+g/f5DJ76nf9dTW122wp5cySkhLC4QiXatm2jTFmtETmFwauojPoXTJsRxVhtBkthcwvHz6BeHvwkmEHTD7CmNG2EEIkEgk8L3fjUkoGDBhwUZBIJIIQoo+twWBZFsJCxB3wVK6d8jxamo5iLhKqJcPGIBDk5RfmhpEAaUlsv18Qc9AqF9xTHseaG748DRjD2NJRCKAwvzDHx4wr8fn92Fpr4SkP13VzCKmurmbx4iU4jvOl3rBlyxaOHj3CwoUL+yRcrTVGK+EpyObMICkr/oKXn6y4KOGr/naW4cVxPqgz2P6idPgJAUZrAKGURns6s28EZ0cqrv/j0otin/lDNW6pD++jIEW+gjS2khow2EoblKdybjsQCPDggw+xdesWZs2ahTrvNgCUUixcuIj9+/cTDAZZtmxZBkOANgatFZ4CNysJRuOKJ34zgrWvO9SdFFyoZjiJbh5eOJRJY2wKC5t540MfPp8vCS0NymgMYDyV4yk65lH20E2ENxzCHO6CCxTSYCJC6bIb8I8v5kxRLfY7bfjsJLZWEgNIo5OEnC/RaJSSkhIaGxtpaWnJkcOHj/DAA8t45pmnmTJlCrW1nxAOhzP2rodWCqMVriJHHA+ktDh8WtMThWAkI6GoJBZpZ9FcwUuvtnHmrOHb1w7H7/flYBitQILyVFJUSlwPW9okjp9DhRN4PSkJJdA9Dm3RLuw7x9K0fh+6KcyI68dh+ey0vfYUCLCV1ijl5XiK53kIIXAcB611DtNaa1avfp6KigqWL1/O+vXrKSgooKOjI8dTVDJ8UAqyHa03vxidDKvsziURbuaJpYM43RLn/jsK+e1fwrieD4SVsZep8BEmeRCV2Z9JhZLWBjydrOOp1RLrZNivZxJr6mTQ4qmcfbYa2xVYIuNOyfABqbVGa51hOyUgyP5Oa000GuWxxx5n8uRyNmzYSCAwEKUUjz66HL/fn2FcJe2M0cnb9ZJkZOcXT2fplMCNtfL7B4ZyuiXObTcVY/kG0tkVY8ktISIxkWOvtQIh0J5GeyotKsW4UQrteWl9m9PFyMd/QLSxk9K55QywC4h0hnAXjEJHnSwMDyPA1lrjeW5OonVdByHAdTP61tZWqqqqmDFjOps2baaiooJVq1aybds2Dhw4gFIq/VuBSRHqEXMgloEmmsrbcTelN5ohBa0s/NlA6o4GmT9rKEc+hxUbFbNmXMb0CsnKLYZeZ/ObXlIgEewhHsy0EjrsIIBETxRCMYwxdBVrShdcy7n6M1xZOZX4kXa6V3/MoBtHM/D6Mlqfr0UUJHOK7bfBGGxtDK7j4mZVGSfhgBB4blJ/7tw5Nm3azNhx41i37q/MmTOHRx95mGB3N36fLxlqiUQGw+h0+HSGIRjOJNpQ6gzdUUNHyDAo7yxL7ynmdFOERT8p5d+fePzuFY+EK5gcNihjOBeGeMrDfL6kJwgJXZ81EwtlSFGhOKOAnlOtqOYeOodqJi27leDpNsbeeyPBD07S9PhOiCkGjMgjoDRdx5qQRf4kKT4brRVSK52Oa0FOGKY61B6eXbkKn8/H1q1bueuuu/jVL5fR3d2NEBkLIUTaXgiB0bq3dCYrBX2b2kB+mD89MgStHe6+uZi3PnJ57h/JcMpu7znP3uhk9ZEKhEr+lQpkb0rT4AyQXLPublytKLvnO3S+8SmtT72PjBuESv4GQHgZe5FyR1spBUIisgZBISUYg5CSuvpDHD9+nBMnTlBZWcn8+bfjuC7SskAI0nOYENCLISRaK7T2+hBhso47/VuSiWUBJpbBrhqPl3cIOntMshe5oE3yszYeSJBuhojeA0JSN3BmGUMmjYBJI+h++yidL+xDt0WTl6czBEgvyy51q7bWCikEMqsMSCEwxpCfl0fNvn3MmzePefPmMf7qcSQSiXRFEkJgSQutdQ6GFKCURhv1JXOxIBaL8cNpA9lTB+/thz2fSOIOyFShEUbguUGEKOwzGPZ6oKXBUn1JcaIxRs2aRHRXA+G3PiO8qwEr5mL1VjFj8BIOQghsL0OQJZP4tlIaKUUqFDId6ZgxY3i16jXuuPMObMsiFOqhpqamzyiw+73dlJeXY4xJY0gpMUZjLtD0WRLOBQ2LZkfY/m4zsbhGacWYy85rDrXh5huu4lijQApzXlugMBJsV2K7mX1rY+G1Rcj7RQX1VdWoaAKlNEwUQKasG62ZNH8C7n87sI2FSGHYyN7qoxBSkv2OEovF2LhxA3Pm/JiqqqqLvp/MnTuXFc88TSgUSmNIKdHaoE1fUooK4L7nFNtXjmDhvBEXbcdrjhiWr3UpyDv//yZ7EEsJ7Kz8Q0EerZWvMf7jxYy/73sXxY59eIb2xW/i8/voLW22FMnwiUSjEWNM2vVN6lAYw8kTx3NyzYWfCnr4oqUFy7LAJMcrIQWRaNRTTiTik31np+Z2Q/kih696urEt+hBiWx6eE/biyoloabC988pDQw+NBau/+n3GlliFNplZwCB8goSXwG5v73jl4MHaFeXl16CUyqk+JxsavtbILS0rKzwE4XCYUCj0djzSXtPTuH2Fb/BPcT2TM+kOKPj/R3spBXnqc7xE8O0uFa7ZrQ6tmCMnYFydm3WK8r8eYHY+kpKW/AiRiPsvq7a29vDIkSMnWpIJJVeU9vtN4vSpBvbsqT6+Zs2LS8821lUXBQZNLLTCE1RB+QXe0r6+WNKiILKL9pOvHz/ynz8v/TTcVF1cEJjoFDJhXHxov/e9b3ATOxIHjq9t2blUAMVA0W2VlUumTZv2VH/BT5w4sXnbtn+ujETDnYAGikZc/f0lV46/td/YXqLtaO3u1bdrSGP/6PIpS8blD3tSC21JIdDGIIxAyOSkntYhMOR+l9YhTLsb/PsbHftWGpfO/wH+lr/CdYGcQQAAAABJRU5ErkJggg==');
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-showannotations-annotation {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEUAAAAVCAYAAAAQAyPeAAAABmJLR0QA/wDoAACU1v3rAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QgdAgcPLA0+6gAABatJREFUWMOtmN9vFFUUx7/nzuyyUNdQCqUUa0oEyo9ETOBFfuiDlvAjATXxhfhgIMbgP2BCjL5BSEwMQYMm4AMaXmxABSkGogHUKgk0LeF3AQMtAq2FbXeX3Zl7zvFhtmuXdsrsLjeZzOTePZ8998w533vvEADs3rWrqbGxcW8ymVxtjEGlTVWRyWav9PX2bvpiz56uixcv8ssbPmuaUd+4NzE52UogqpgNhZfPXrl/r29T98kvu9IPL/G7iRVNc2Y2762tm9ZqyFTGJkBVMJQaunL93vVNh7PdXbRzx44ZCxct6n69tbVBmCGqqKYlEpNw7uw5r6OjY/n+Y5lbzXMWdS9duqYhnYuDq0ATgGSN4vbNM9757o7l0w/vu7Vy0Yrure9tbUg8VFAVcDUA6ibh0C9HvPaf25e7tbW1e5a8tKQhl8vhabThYR/zW1riN2/caHsm+eDsC/OWNQwMxwGtnj3wgFA3c0n82ak322ZPmXV2/ep1DZPu+lBo9fheH61LVsW7znS2ucaYFfX19UinMwCAlgULI3OuXL40br/rulDVZgOTmJJ8HoMpCwA4sHNWZPamD/8Zt9/jGqhosyGTWNzYglx/CgAw++uNkdl9m38Ytz+pCZBqs0tElM/nYa0tDv57YeCJ4LrF00tsHq9/x3FADijnAZZRPptDyogA4xi48TjhkQdhLps92qbEb98gFo/DFRGybOH7ftkZF2ajqhARqDBZBkJiN2ELsyECVAQAiFkgVspmh9mwEQAKl0XBlkveet3i6REdt6GqKKoQYVgG/FEiGJXthwgnGQWrQAGo5ZK3HpUdlinCBgrAVQkCMjLBPzv+KONt2gn/WIXhM+AXfFjzwZ3oWRhWPgZQYcAAbBlsGSCg5+0DgZhTsYbHPhfuzFw6XmjGGoAAl0XAbEMnuHLVK5En8tvpU8VM4aB8wAyEvBgc/6oxMrv1/SCg1hTKhxTMDOHxS2H+oXcis6+++e2o8gFcEYGIBNELaVEFbIRhjAk0RSXIFIvitk0VJVu4coWXCBBhgAhiBWKr93uEIYagVAiKtX5FQhsmvIRAaEUsHnnAo+rRyHrBPa4jQQHyqWHkUpmq2blUOsiQuAuowhVV+J4P3/MmjGakoIwwVIrlM5gGUmmtmj1YYMRigDKDDPDgah8eDWWqZj+81hcEJeZChOEKSzGdaawmof2nI+P2j77jMc0iIqjIyNIZutuc+1ZfGWefUc8SrD6GAeLxtfVk/bYwnR3zW/D/Ig4ALjMDZECFg+DatesiO3qs/SgoZIkQYYjYksn0HJwdmR0WMAUgagEDGB8whfVh1eD2yOzT07aN67ehIFKuCMMQwYxSv6gCZUIOvYYAZoEojzkXR2VPdDAcyUBHAKeC3bITos1OsCLDZRYYQ6AKTvVhNsYYqAp0ghWtmibCUAO4voHrl+93mI0LM7L6MMgYjP6OElWgwr69BEuyQpQrFr+Jv9sIQIDDBJepbPZom5J+Q0H5ZLLZjKoWS+HXE8crd7YoKYRMNmvZy2RixqtIWEMn5FhYL21z7GXEKFwbCEG38zEib2ntGKkFoKAYIW/zMP39A/vOneuEG4+DHKeqyzgO3JiLdDqNoaGho7lM/77h24cQc+mplI0xhEl8CzafOvqA0/tO8HnEjAu3kDEumyc8h40TYurgfiKDDPwfnc7OzotNTU0LHIOW+pkNVTv+980bOHny1LVdu3ZvuXu761RNcuqCKU66hScvHkcyo1+OcTA5cxz917+7dun3z7dcSPeeqpucXOBNQcvcXPUl+VdtLw7nz17bc6d9CwGoA1CzccOGzcuWLfukWnhPT8/+traD2zPZ9CAAAVDz3LxXN8+ev75qts3fv9x54tM3BCiyX5vx4ua5iVkfCYljiCCqICWQCU7qxT4QFKVjxT6Q9vupb74f+Gu7+hj8D6dPKX8nggZiAAAAAElFTkSuQmCC');
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-statistics-annotation {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEUAAAAVCAYAAAAQAyPeAAAABmJLR0QA/wDoAACU1v3rAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QgdAhEHPk4DDwAABcNJREFUWMOtV21oHOcRfmb2vfPZyoWoimVFjhKFfMh1oC7EUGo3hDRRCAkopT/6w5DEtWkhkNISSH8VTP849IMW4QSHYkMikz+pyIcd7IQEBxtS44AtpBAnjr9aWwq2ZWSfdHe+292Z6Y+TTnvWrk+n9QvLDs++M8zOO/PMvAQAOwYHe7q7u3fl8/mnmBlLXWaGUrl8cmJ8fNMbO3eOnjhxQn468M+elZ3du3LL8/0EoiXbhsGvlk9evjSxaezQm6PFa9/I5tzGnvtW9e5q7/hBPxMvzTYBZorpwvTJM5fObNpXHhulv7z22sofrl079mR/f5eKQM2QZuVyy3D82HH/yJEjG4Y+Lp3vvW/t2COPPN1VrGQhKUwTgHyb4cK5L/2vxo5suHPf7vM/W7tx7KXfvNSVu2agFMaNAXQsw/sHP/IPfHJgg2tvb9+57sfruiqVCm7FmpkJ8FBfX/bc2bPDt+WvHrv/wfVdV2aygKW3feUqoWPVuuztd5wbXr3irmPPPvVM17KLAQyW3vx4gP51j2ZHvxwZdsy8sbOzE8ViqWU7jz/+87r8+ecH67JzDmbWy+Dcivw9mCqELdve8aqry7/727y+L20wtV4mzj3c3YfKZKH1bP7rhrpc+eN/6nLeciCzXkdEVK1WEYZhqkBH9Q0Gz/NAHqjiA6GkO8SoPhHAHsNls4TrPlTSGY/qW8DIZLNwqkqhhAiCIJXxqL6ZQVVhKhQKkDLeDfpEgKkCAIkoNNR0QYnoCysAgxM1SCgNJz0w8Fxd3rv3w5YzBQSoGVQFoQBBhATf2papy5v/vLiDiOoTG8QUBsBCaTjp21+fL+fplw+2nCkqDAPgTGsBSSqfxZbVjftUBKaCQIBAkn52kVkYLR8GTAVgQEKBhFJrTTesBtxm29fcO7ovEhQOGSDAiSpEbnFQCJBa+UAESCr7xdJBdF/Is+VDBhGBiiZkgC6xfACnqlDVhoglRfLmjkcizlzjFNNapoSIHduiuFmjfDOiVRWACBoqNIHFdZHsHt2nTDCaDUoYBolEO4e/8MKLdWxo6O2bEi2hRrSqIa77wPUE6pjD9/9jnmeeeWXh5rI/L2dtLihAtTCDSiF+lKgUigCAnvd+Vccu/PLdxH0A4LIOMINTMwR+gMD344MSgzfFTOvlM1UECsX40WoqBm+GZTKAiYAYuPrdBK5PzwelJ6Jz7dRESxgAuIyDqsCpaD1tKWG8jsPsJvuICKY61zoTp01bImZa6z4sAEmCjzF4HMY3kDgAOBEBiEFJF8E4nHmhI9F9xFAVqIa3YrpfECC1EGCAA4AT+kAcHodRBGOqna5TFTAROOECG4c3w5gAEYWapLgXJ18M5zLQU8BL4NM4vBnm1ToynIiCmUAJ3sfhzTBmhpnCUo7giR1DBcaACxguiPc7Dm+GOfBc9xEQM5gZz0c6zNx6cfOvW8L2DL0925INavNBOfqv7AKdVrGf/NafbdkKEOAJwQnh3onfL9C5//wfWsL+t3oQjqlWPqVyuWRmYCK8s2eoYehLktGEOIkJpXI5FL9UyrDf8ENpl/NChH4xrIhfUja4kDCxakcTj28caReOuA4EyhCqYRU8OXll9/HjI3DZLMjzwJ4Hmn2S5KSHPQ8u41AsFjE9Pb2/UprcPXPhfWTcrSEWZsIyOY+wWth/VYq7P5OvkGEHN5sxTriJnPQmZMzD5VwJJQR7vZGRkRM9PT1rPEZf56qu1I7/99xZHDp0+NTg4I6tFy+MHm7L37FmhVfsk+UPx1Dm4h+PPSwvfYrJM/8+9c0Xr2/9ujh+uGN5fo2/An0PVO5M7ffR9nHsqx47tfP7A1sJQAeAtucGBrasX79+W1rjp0+fHhoefm97qVycAqAA2u5+8LEtqx96NrXtsHr525HP/v4LBeq2n1j5oy0P5O76k5J6TAQ1AxmBuHZTr2MgGBq/1TGQTQaFPR9cObrdAkz9Hw14UPPRoMvjAAAAAElFTkSuQmCC');
|
||||
}
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --- */
|
||||
|
||||
.vjs-default-skin .vjs-back-anpanel-annotation{
|
||||
float: left;
|
||||
left: 0em;
|
||||
right: 0em;
|
||||
position:absolute;
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
width: auto;
|
||||
/*font-size: .3em;*/
|
||||
font-size: .9em;
|
||||
-webkit-transition: top .4s,height .4s,font-size .4s,-webkit-transform .4s;
|
||||
-moz-transition: top .4s,height .4s,font-size .4s,-moz-transform .4s;
|
||||
-o-transition: top .4s,height .4s,font-size .4s,-o-transform .4s;
|
||||
transition: top .4s,height .4s,font-size .4s,transform .4s;
|
||||
opacity:1;
|
||||
visibility:visible;
|
||||
transition-delay:0s;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --> RangeSelectorDisplay --- */
|
||||
|
||||
.vjs-default-skin .vjs-rangeselector-anpanel-annotation{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: -1em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-back-anpanel-annotation.statistics .vjs-rangeselector-anpanel-annotation{
|
||||
z-index:2;
|
||||
}
|
||||
|
||||
/* RangeSelectorLeft */
|
||||
.vjs-default-skin .vjs-leftselector-anpanel-annotation{
|
||||
height: 100%;
|
||||
margin-top: 1em;
|
||||
width:0%;
|
||||
float:left;
|
||||
position:absolute;
|
||||
left: 0%;
|
||||
}
|
||||
.vjs-default-skin .vjs-leftselector-anpanel-annotation .vjs-selector-arrow{
|
||||
z-index:10;
|
||||
border-left: 1em solid #FFE800;
|
||||
cursor: e-resize;
|
||||
}
|
||||
.vjs-default-skin .vjs-leftselector-anpanel-annotation .vjs-leftselector-back{
|
||||
right:100%;
|
||||
border-right: 1px dashed #FFE800;
|
||||
}
|
||||
.vjs-default-skin .vjs-leftselector-anpanel-annotation.include .vjs-leftselector-back{
|
||||
border-right: 1px dashed rgb(255, 163, 0);
|
||||
}
|
||||
.vjs-default-skin .vjs-leftselector-anpanel-annotation.include .vjs-selector-arrow{
|
||||
border-left: 1em solid rgb(255, 163, 0);
|
||||
}
|
||||
|
||||
/* RangeSelectorRight */
|
||||
.vjs-default-skin .vjs-rightselector-anpanel-annotation{
|
||||
height: 100%;
|
||||
margin-top: 1em;
|
||||
width:100%;
|
||||
float:right;
|
||||
position:absolute;
|
||||
}
|
||||
.vjs-default-skin .vjs-rightselector-anpanel-annotation .vjs-selector-arrow{
|
||||
z-index:20;
|
||||
border-right: 1em solid #FFE800;
|
||||
margin-left: -1em;
|
||||
cursor: w-resize;
|
||||
}
|
||||
.vjs-default-skin .vjs-rightselector-anpanel-annotation .vjs-rightselector-back{
|
||||
border-left: 1px dashed #FFE800;
|
||||
}
|
||||
.vjs-default-skin .vjs-rightselector-anpanel-annotation.include .vjs-rightselector-back{
|
||||
border-left: 1px dashed rgb(255, 163, 0);
|
||||
}
|
||||
.vjs-default-skin .vjs-rightselector-anpanel-annotation.include .vjs-selector-arrow{
|
||||
border-right: 1em solid rgb(255, 163, 0);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-leftselector-back,
|
||||
.vjs-default-skin .vjs-rightselector-back{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position:absolute;
|
||||
background-color: rgba(0,0,0,0.6);
|
||||
}
|
||||
.vjs-default-skin .vjs-selector-arrow{
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 1em solid transparent;
|
||||
border-bottom: 1em solid transparent;
|
||||
opacity: 0.8;
|
||||
position: absolute;
|
||||
top: -2em;
|
||||
}
|
||||
|
||||
/* RangeSelectorBar */
|
||||
.vjs-default-skin .vjs-barselector-anpanel-annotation{
|
||||
height: 2em;
|
||||
margin-top: -1em;
|
||||
background-color: rgba(0,0,0,0.6);
|
||||
border: 1px solid rgba(255,255,255,0.6);
|
||||
position: absolute;
|
||||
float: left;
|
||||
visibility:visible;
|
||||
transition-delay:0s;
|
||||
}
|
||||
.vjs-default-skin .vjs-barselector-anpanel-annotation.disable{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
-webkit-transition: visibility 0.5s linear 0.5s,opacity 0.5s linear;
|
||||
-moz-transition: visibility 0.5s linear 0.5s,opacity 0.5s linear;
|
||||
-o-transition: visibility 0.5s linear 0.5s,opacity 0.5s linear;
|
||||
transition:visibility 0.5s linear 0.5s,opacity 0.5s linear;
|
||||
}
|
||||
.vjs-default-skin .vjs-barselector-anpanel-annotation .vjs-barselector-left{
|
||||
float: left;
|
||||
left: 1em;
|
||||
}
|
||||
.vjs-default-skin .vjs-barselector-anpanel-annotation .vjs-barselector-right{
|
||||
right: 1em;
|
||||
float: right;
|
||||
}
|
||||
.vjs-default-skin .vjs-barselector-anpanel-annotation .vjs-barselector-right,
|
||||
.vjs-default-skin .vjs-barselector-anpanel-annotation .vjs-barselector-left{
|
||||
height: 2em;
|
||||
font-size: 1.3em;
|
||||
position: absolute;
|
||||
}
|
||||
.vjs-default-skin .vjs-rangeselector-anpanel-annotation.active .vjs-barselector-anpanel-annotation{
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --> AnDisplay --- */
|
||||
|
||||
.vjs-default-skin .vjs-anpanel-annotation{
|
||||
float: left;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0em;
|
||||
right: 0em;
|
||||
position:absolute;
|
||||
/*background-color: #FFE800;
|
||||
background: #FFE800;
|
||||
background: -moz-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFE800), to(#A69700));
|
||||
background: -webkit-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -o-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -ms-linear-gradient(top, #FFE800, #A69700);
|
||||
background: linear-gradient(top, #FFE800, #A69700);*/
|
||||
opacity: 0.8;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.vjs-default-skin .vjs-anpanel-annotation .annotation{
|
||||
height: 1em;
|
||||
float: left;
|
||||
width: 100%;
|
||||
left: 0em;
|
||||
right: 0em;
|
||||
cursor:pointer;
|
||||
position:absolute;
|
||||
background-color: #FFE800;
|
||||
background: #FFE800;
|
||||
background: -moz-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFE800), to(#A69700));
|
||||
background: -webkit-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -o-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -ms-linear-gradient(top, #FFE800, #A69700);
|
||||
background: linear-gradient(top, #FFE800, #A69700);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-anpanel-annotation .annotation.active {
|
||||
background-color: #2DCF02;
|
||||
background: #2DCF02;
|
||||
background: -moz-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#2DCF02), to(#114F01));
|
||||
background: -webkit-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -o-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -ms-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: linear-gradient(top, #2DCF02, #114F01);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-anpanel-annotation .annotation.point {
|
||||
border-radius: 50%;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin-left: -0.4em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-back-anpanel-annotation.statistics .vjs-anpanel-annotation{
|
||||
visibility:hidden;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --> AnStat --- */
|
||||
.vjs-default-skin .vjs-anstat-annotation{
|
||||
float: left;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0em;
|
||||
right: 0em;
|
||||
position: absolute;
|
||||
opacity: 0.8;
|
||||
visibility:visible;
|
||||
transition-delay:0s;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-anstat-annotation.disable{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-totan-anstat-annotation,
|
||||
.vjs-default-skin .vjs-maxcon-anstat-annotation{
|
||||
position: absolute;
|
||||
top: 0.3em;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
border-radius: 0.5em;
|
||||
padding: 0.1em;
|
||||
color: rgb(255, 163, 0);
|
||||
}
|
||||
.vjs-default-skin .vjs-totan-anstat-annotation{
|
||||
float: right;
|
||||
right:1em;
|
||||
}
|
||||
.vjs-default-skin .vjs-maxcon-anstat-annotation{
|
||||
float: left;
|
||||
left:1em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --> --- */
|
||||
|
||||
.vjs-default-skin .dashed-line{
|
||||
float: left;
|
||||
right: 0em;
|
||||
position:absolute;
|
||||
color: #2DCF02;
|
||||
border-left:0.23em dashed #2DCF02;
|
||||
border-right:0.23em dashed #2DCF02;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.vjs-default-skin .dashed-line.point{
|
||||
border-right:0;
|
||||
}
|
||||
|
||||
.vjs-default-skin .box-dashed-line{
|
||||
height: 1em;
|
||||
float: left;
|
||||
right: 0em;
|
||||
color: #2DCF02;
|
||||
position:absolute;
|
||||
background-color:#2DCF02;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.vjs-default-skin .boxup-dashed-line{
|
||||
height: 1em;
|
||||
float: left;
|
||||
right: 0em;
|
||||
color: #2DCF02;
|
||||
position:absolute;
|
||||
opacity: 0.8;
|
||||
background-color: #2DCF02;
|
||||
background: #2DCF02;
|
||||
background: -moz-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#2DCF02), to(#114F01));
|
||||
background: -webkit-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -o-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -ms-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: linear-gradient(top, #2DCF02, #114F01);
|
||||
z-index: 4;
|
||||
-webkit-transition: top 1s,-webkit-transform .4s;
|
||||
-moz-transition: top 1s,-moz-transform .4s;
|
||||
-o-transition: top 1s,-o-transform .4s;
|
||||
transition: top 1s,transform .4s;
|
||||
}
|
||||
|
||||
.vjs-default-skin .boxup-dashed-line.point{
|
||||
border-radius: 50%;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin-left: -0.4em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --> BackAnDisplayScroll --- */
|
||||
|
||||
.vjs-default-skin .vjs-down-scroll-annotation,
|
||||
.vjs-default-skin .vjs-up-scroll-annotation{
|
||||
width:2em;
|
||||
height:2em;
|
||||
float: left;
|
||||
right: 0em;
|
||||
position:absolute;
|
||||
cursor: pointer;
|
||||
border-left: 1em solid transparent;
|
||||
border-right: 1em solid transparent;
|
||||
/*font-size: .3em;*/
|
||||
font-size: .9em;
|
||||
-webkit-transition: top .4s,height .4s,font-size .4s,-webkit-transform .4s;
|
||||
-moz-transition: top .4s,height .4s,font-size .4s,-moz-transform .4s;
|
||||
-o-transition: top .4s,height .4s,font-size .4s,-o-transform .4s;
|
||||
transition: top .4s,height .4s,font-size .4s,transform .4s;
|
||||
opacity: 0.8;
|
||||
transition-delay:0s;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-up-scroll-annotation{
|
||||
border-bottom: 1em solid black;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-down-scroll-annotation{
|
||||
top: -3em;
|
||||
border-top: 1em solid black;
|
||||
}
|
||||
.vjs-default-skin .vjs-scroll-anpanel-annotation.disable,
|
||||
.vjs-default-skin .vjs-back-anpanel-annotation.disable{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
/*-webkit-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
-moz-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
-o-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
transition:visibility 1s linear 1s,opacity 1s linear;*/
|
||||
}
|
||||
|
||||
.vjs-default-skin:hover .vjs-back-anpanel-annotation,
|
||||
.vjs-default-skin:hover .vjs-down-scroll-annotation,
|
||||
.vjs-default-skin:hover .vjs-up-scroll-annotation {
|
||||
font-size: .9em;
|
||||
-webkit-transition: top .2s,height .2s,font-size .2s,-webkit-transform .2s;
|
||||
-moz-transition: top .2s,height .2s,font-size .2s,-moz-transform .2s;
|
||||
-o-transition: top .2s,height .2s,font-size .2s,-o-transform .2s;
|
||||
transition: top .2s,height .2s,font-size .2s,transform .2s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --> BackAnDisplayScroll--> BackAnDisplayScrollBar --- */
|
||||
|
||||
.vjs-default-skin .vjs-scrollbar-anpanel-annotation{
|
||||
float: left;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
right: 0.5em;
|
||||
width: 1em;
|
||||
/*font-size: .3em;*/
|
||||
font-size: .9em;
|
||||
background-color: black;
|
||||
opacity: 0.8;
|
||||
visibility:visible;
|
||||
transition-delay:0s;
|
||||
-webkit-transition: top .4s,height .4s,font-size .4s,-webkit-transform .4s;
|
||||
-moz-transition: top .4s,height .4s,font-size .4s,-moz-transform .4s;
|
||||
-o-transition: top .4s,height .4s,font-size .4s,-o-transform .4s;
|
||||
transition: top .4s,height .4s,font-size .4s,transform .4s;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-scrollbar-anpanel-annotation.disable{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
-webkit-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
-moz-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
-o-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
transition:visibility 1s linear 1s,opacity 1s linear;
|
||||
}
|
||||
.vjs-default-skin .vjs-scrollbar-anpanel-annotation:hover{
|
||||
opacity: 0.8;
|
||||
visibility:visible;
|
||||
transition-delay:0s;
|
||||
}
|
||||
|
||||
.vjs-default-skin:hover .vjs-scrollbar-anpanel-annotation{
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-scrollbar-selector{
|
||||
width: 1em;
|
||||
background-color: gray;
|
||||
border: 1px solid black;
|
||||
position:absolute;
|
||||
height: 3em;
|
||||
border-radius: 0.4em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --- ControlBar --> BackAnDisplay --> BackAnDisplayScroll--> BackAnDisplayScrollTime --- */
|
||||
.vjs-default-skin .vjs-down-scrolltime-annotation,
|
||||
.vjs-default-skin .vjs-up-scrolltime-annotation{
|
||||
width: 100%;
|
||||
height:1em;
|
||||
float: left;
|
||||
position:absolute;
|
||||
font-size: .9em;
|
||||
opacity: 0.8;
|
||||
transition-delay:0s;
|
||||
right: 3em;
|
||||
text-align: right;
|
||||
margin-top:0.2em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-down-scrolltime-annotation{
|
||||
top: -2.6em;
|
||||
margin-top: -0.2em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-scrolltime-anpanel-annotation span{
|
||||
font-size: 1.3em;
|
||||
background-color: rgba(0,0,0,1);
|
||||
border-radius: 0.5em;
|
||||
padding: 0.1em;
|
||||
border: 0.1em solid white;
|
||||
padding-left: 0.4em;
|
||||
padding-right: 0.4em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ---------------- Modify the CSS of Annotator plugin ---------------- */
|
||||
.annotator-wrapper.vjs-fullscreen .annotator-adder,
|
||||
.annotator-wrapper.vjs-fullscreen .annotator-outer,
|
||||
.annotator-wrapper.vjs-fullscreen .annotator-widget,
|
||||
.annotator-wrapper.vjs-fullscreen .annotator-notice {
|
||||
z-index:3000000000; /*To fix full-screen*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ---------------- Modify the CSS of Video-js plugin ---------------- */
|
||||
|
||||
.vjs-default-skin *, .vjs-default-skin *:before, .vjs-default-skin *:after {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ---------------- Modify the CSS of Range Slider plugin ---------------- */
|
||||
|
||||
/* Selection bar in green color */
|
||||
.vjs-default-skin .vjs-rangeslider-holder.locked span.annotator-hl > div.vjs-selectionbar-RS {
|
||||
background-color: #2DCF02;
|
||||
background: #2DCF02;
|
||||
background: -moz-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#2DCF02), to(#114F01));
|
||||
background: -webkit-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -o-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: -ms-linear-gradient(top, #2DCF02, #114F01);
|
||||
background: linear-gradient(top, #2DCF02, #114F01);
|
||||
}
|
||||
|
||||
.vjs-default-skin div.vjs-rangeslider-holder.locked .vjs-rangeslider-handle > div.vjs-selectionbar-line-RS {
|
||||
background-color: #2DCF02;
|
||||
}
|
||||
|
||||
.vjs-default-skin div.vjs-rangeslider-holder.locked .vjs-rangeslider-handle > div.vjs-selectionbar-arrow-RS {
|
||||
border-top-color: #2DCF02;
|
||||
}
|
||||
|
||||
186
common/static/css/vendor/ova/rangeslider.css
vendored
@@ -1,186 +0,0 @@
|
||||
/*Range Slider Bar Time*/
|
||||
.vjs-default-skin .vjs-timebar-RS{
|
||||
color: red;
|
||||
top: -1em;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background: rgba(100,100,100,.5);/*Quitar*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*Selection Range Slider Bar Selected*/
|
||||
.vjs-default-skin .vjs-rangeslider-holder{height: 100%;}
|
||||
|
||||
.vjs-default-skin .vjs-selectionbar-RS{
|
||||
height: 100%;
|
||||
float: left;
|
||||
width: 100%;
|
||||
left: 0em;
|
||||
right: 0em;
|
||||
position:absolute;
|
||||
background-color: #FFE800;
|
||||
background: #FFE800;
|
||||
background: -moz-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#FFE800), to(#A69700));
|
||||
background: -webkit-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -o-linear-gradient(top, #FFE800, #A69700);
|
||||
background: -ms-linear-gradient(top, #FFE800, #A69700);
|
||||
background: linear-gradient(top, #FFE800, #A69700);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.vjs-default-skin div.vjs-rangeslider-holder.locked > div.vjs-selectionbar-RS {
|
||||
background-color: #FF6565;
|
||||
background: #FF6565;
|
||||
background: -moz-linear-gradient(top, #FF6565, #300000);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#FF6565), to(#300000));
|
||||
background: -webkit-linear-gradient(top, #FF6565, #300000);
|
||||
background: -o-linear-gradient(top, #FF6565, #300000);
|
||||
background: -ms-linear-gradient(top, #FF6565, #300000);
|
||||
background: linear-gradient(top, #FF6565, #300000);
|
||||
}
|
||||
|
||||
|
||||
/*Arrow and Handle*/
|
||||
.vjs-default-skin div.vjs-rangeslider-handle {
|
||||
position: absolute;
|
||||
margin-top: 0;
|
||||
cursor: pointer !important;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-selectionbar-left-RS{height: 100%;left: 0;z-index:10}
|
||||
.vjs-default-skin .vjs-selectionbar-right-RS{height: 100%;left: 100%;z-index:20}
|
||||
|
||||
.vjs-default-skin div.vjs-selectionbar-left-RS,
|
||||
.vjs-default-skin div.vjs-selectionbar-right-RS {
|
||||
top: 0em;
|
||||
position: absolute;
|
||||
width:0em;
|
||||
}
|
||||
|
||||
.vjs-default-skin div.vjs-selectionbar-arrow-RS {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 1em solid transparent;
|
||||
border-right: 1em solid transparent;
|
||||
border-top: 1em solid #FFF273;
|
||||
margin-left: -1em;
|
||||
opacity: 0.8;
|
||||
|
||||
position: absolute;
|
||||
top: -1em;
|
||||
}
|
||||
.vjs-default-skin div.vjs-rangeslider-handle.active > div.vjs-selectionbar-arrow-RS {
|
||||
border-top-color: #5F5FB3;
|
||||
}
|
||||
|
||||
.vjs-default-skin div.vjs-rangeslider-holder.locked .vjs-rangeslider-handle > div.vjs-selectionbar-arrow-RS {
|
||||
border-top-color: #FF6565;
|
||||
}
|
||||
|
||||
.vjs-default-skin div.vjs-selectionbar-line-RS {
|
||||
width: 1px;
|
||||
height: 1em;
|
||||
background-color: #FFF273;
|
||||
|
||||
position:absolute;
|
||||
top: 0em;
|
||||
}
|
||||
.vjs-default-skin div.vjs-rangeslider-handle.active > div.vjs-selectionbar-line-RS {
|
||||
background-color: #5F5FB3;
|
||||
}
|
||||
|
||||
.vjs-default-skin div.vjs-rangeslider-holder.locked .vjs-rangeslider-handle > div.vjs-selectionbar-line-RS {
|
||||
background-color: #FF6565;
|
||||
}
|
||||
|
||||
|
||||
/* Time Panel */
|
||||
.vjs-default-skin .vjs-timepanel-RS{
|
||||
width: 100%;
|
||||
height: 1em;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
top: -2em;
|
||||
position: absolute;
|
||||
visibility:visible;
|
||||
opacity:1;
|
||||
transition-delay:0s;
|
||||
}
|
||||
.vjs-default-skin .vjs-timepanel-RS.disable{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
-webkit-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
-moz-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
-o-transition: visibility 1s linear 1s,opacity 1s linear;
|
||||
transition:visibility 1s linear 1s,opacity 1s linear;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-timepanel-left-RS,
|
||||
.vjs-default-skin .vjs-timepanel-right-RS{
|
||||
font-weight: normal;
|
||||
font-size: 1em;
|
||||
color: #666666;
|
||||
border: 1px solid #666666;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
position: absolute;
|
||||
height:116%;
|
||||
padding-right: 0.3em;
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
.vjs-default-skin .vjs-timepanel-left-RS{
|
||||
left:0.5%
|
||||
}
|
||||
.vjs-default-skin .vjs-timepanel-right-RS{
|
||||
left:92%
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Control Time Panel */
|
||||
.vjs-default-skin .vjs-controltimepanel-RS{
|
||||
width: 18em;
|
||||
font-size: 1em;
|
||||
line-height: 3em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-controltimepanel-RS input{
|
||||
width: 1.5em;
|
||||
background: rgba(102, 168, 204, 0.16);
|
||||
border: 1px solid transparent;
|
||||
color: black;
|
||||
font-size: 1em;
|
||||
margin-left: 2px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-controltimepanel-left-RS{
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
.vjs-default-skin .vjs-controltimepanel-right-RS{
|
||||
float:right;
|
||||
width: 48%;
|
||||
}
|
||||
.vjs-default-skin .vjs-controltimepanel-RS input{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------- Video-js plugin ---------------- */
|
||||
|
||||
.vjs-default-skin *, .vjs-default-skin *:before, .vjs-default-skin *:after {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
.annotator-viewer div:first-of-type.richText-annotation *,
|
||||
.annotator-viewer div:first-of-type.richText-annotation{
|
||||
font-style: normal;
|
||||
font-weight: inherit;
|
||||
text-align: inherit;
|
||||
}
|
||||
.annotator-viewer div:first-of-type.richText-annotation{
|
||||
padding-top: 22px;
|
||||
}
|
||||
|
||||
/* Fix in the tinymce */
|
||||
.annotator-viewer div:first-of-type.richText-annotation strong{
|
||||
font-weight: bold;
|
||||
}
|
||||
.annotator-viewer div:first-of-type.richText-annotation em{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.mce-floatpanel {
|
||||
z-index: 700000000!important;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
div.mce-tinymce.mce-container.mce-panel {
|
||||
min-width:400px;
|
||||
}
|
||||
|
||||
/* Some change in the design of Annotator */
|
||||
.annotator-editor .annotator-widget{
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
/*Rubric icon*/
|
||||
.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;
|
||||
}
|
||||
|
||||
/* Fixes conflicting design between tinymce css and annotator css */
|
||||
.mce-ico.mce-i-resize {
|
||||
font-family: 'tinymce';
|
||||
}
|
||||
205
common/static/css/vendor/ova/share-annotator.css
vendored
@@ -1,205 +0,0 @@
|
||||
/* Editor */
|
||||
.share-container-annotator {
|
||||
display: block;
|
||||
min-width: 100%;
|
||||
border: none;
|
||||
margin: 0;
|
||||
color: rgb(60, 60, 60);
|
||||
background: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-o-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
resize: none;
|
||||
padding-left: 0.6em;
|
||||
padding-right: 1em;
|
||||
height: 3.1em;
|
||||
}
|
||||
|
||||
.share-container-annotator .share-text-annotator {
|
||||
float:left;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.annotator-editor .share-container-annotator .share-text-annotator {
|
||||
height: 2.1em;
|
||||
}
|
||||
|
||||
.share-container-annotator .share-button, .annotator-wrapper .share-button {
|
||||
top: 0.3em;
|
||||
outline: 0;
|
||||
float:left;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-left:0.3em;
|
||||
height: 2.5em;
|
||||
width: 2.5em;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 2.5em;
|
||||
}
|
||||
|
||||
.share-container-annotator .share-button:hover, .annotator-wrapper .share-button:hover {
|
||||
opacity: .6;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Popup */
|
||||
|
||||
.annotator-wrapper .share-popup-overlay-bg {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height:100%;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
background: #000; /* fallback */
|
||||
background: rgba(0,0,0,0.75);
|
||||
padding: 0;
|
||||
}
|
||||
.annotator-wrapper .share-popup-overlay-bg .share-popup {
|
||||
background: #fff;
|
||||
padding: 1% !important;
|
||||
width: 30%;
|
||||
position: relative;
|
||||
top: 15%;
|
||||
left: 50%;
|
||||
margin: 0 0 0 -17% !important; /* add negative left margin for half the width to center the div */
|
||||
cursor: default;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.9);
|
||||
}
|
||||
.annotator-wrapper .share-popup-overlay-bg .share-popup-copy,
|
||||
.annotator-wrapper .share-popup-overlay-bg .share-popup-title {
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: 21px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 20px;
|
||||
color: #222;
|
||||
}
|
||||
.annotator-wrapper .share-popup-overlay-bg .share-popup-uri {
|
||||
width:100%;
|
||||
border: 1px solid rgb(144, 144, 144);
|
||||
height: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.annotator-wrapper .share-popup-overlay-bg .share-popup-copy {
|
||||
font-size: 15px;
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding:0;
|
||||
margin: 1.0em 0em 0.5em 0em !important;
|
||||
}
|
||||
.annotator-wrapper .share-popup-overlay-bg .share-popup .share-button {
|
||||
width: 50%;
|
||||
padding: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-o-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
alignment-baseline: central;
|
||||
background-position: 0.5em;
|
||||
height: 4em;
|
||||
padding-top: 1.3em !important;
|
||||
}
|
||||
/* Close button */
|
||||
.annotator-wrapper .share-popup-overlay-bg .close-btn {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: 0 12px 0 12px;
|
||||
color: rgb(54, 54, 54);
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.75);
|
||||
text-decoration: none;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
border: 1px solid rgb(162, 162, 162);
|
||||
background-color: rgb(212, 212, 212);
|
||||
background-image: -webkit-gradient( linear, left top, left bottom, from(rgb(245, 245, 245)), color-stop(0.5, rgb(210, 210, 210)), color-stop(0.5, rgb(190, 190, 190)), to(rgb(210, 210, 210)) );
|
||||
background-image: -moz-linear-gradient( to bottom, rgb(245, 245, 245), rgb(210, 210, 210) 50%, rgb(190, 190, 190) 50%, rgb(210, 210, 210) );
|
||||
background-image: -webkit-linear-gradient( to bottom, rgb(245, 245, 245), rgb(210, 210, 210) 50%, rgb(190, 190, 190) 50%, rgb(210, 210, 210) );
|
||||
background-image: linear-gradient( to bottom, rgb(245, 245, 245), rgb(210, 210, 210) 50%, rgb(190, 190, 190) 50%, rgb(210, 210, 210) );
|
||||
-webkit-box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.2), inset 0 0 1px rgba(255, 255, 255, 0.8);
|
||||
-moz-box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.2), inset 0 0 1px rgba(255, 255, 255, 0.8);
|
||||
-o-box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.2), inset 0 0 1px rgba(255, 255, 255, 0.8);
|
||||
box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.2), inset 0 0 1px rgba(255, 255, 255, 0.8);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-o-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.annotator-wrapper .share-popup-overlay-bg .close-btn:hover {
|
||||
outline: none;
|
||||
border-color: rgb(67, 90, 160);
|
||||
background-color: rgb(56, 101, 249);
|
||||
background-image: -webkit-gradient( linear, left top, left bottom, from(rgb(118, 145, 251)), color-stop(0.5, rgb(80, 117, 251)), color-stop(0.5, rgb(56, 101, 249)), to(rgb(54, 101, 250)) );
|
||||
background-image: -moz-linear-gradient( to bottom, rgb(118, 145, 251), rgb(80, 117, 251) 50%, rgb(56, 101, 249) 50%, rgb(54, 101, 250) );
|
||||
background-image: -webkit-linear-gradient( to bottom, rgb(118, 145, 251), rgb(80, 117, 251) 50%, rgb(56, 101, 249) 50%, rgb(54, 101, 250) );
|
||||
background-image: linear-gradient( to bottom, rgb(118, 145, 251), rgb(80, 117, 251) 50%, rgb(56, 101, 249) 50%, rgb(54, 101, 250) );
|
||||
color: rgb(255, 255, 255);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
|
||||
.annotator-wrapper .share-popup-overlay-bg .close-btn:active {
|
||||
border-color: rgb(112, 12, 73);
|
||||
background-color: rgb(209, 46, 142);
|
||||
background-image: -webkit-gradient( linear, left top, left bottom, from(rgb(252, 124, 202)), color-stop(0.5, rgb(232, 93, 178)), color-stop(0.5, rgb(209, 46, 142)), to(rgb(255, 0, 156)) );
|
||||
background-image: -moz-linear-gradient( to bottom, rgb(252, 124, 202), rgb(232, 93, 178) 50%, rgb(209, 46, 142) 50%, rgb(255, 0, 156) );
|
||||
background-image: -webkit-linear-gradient( to bottom, rgb(252, 124, 202), rgb(232, 93, 178) 50%, rgb(209, 46, 142) 50%, rgb(255, 0, 156) );
|
||||
background-image: linear-gradient( to bottom, rgb(252, 124, 202), rgb(232, 93, 178) 50%, rgb(209, 46, 142) 50%, rgb(255, 0, 156) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Viewer */
|
||||
.annotator-viewer .share-viewer-annotator div.share-text-annotator,
|
||||
.annotator-viewer .share-viewer-annotator div.share-button,
|
||||
.annotator-wrapper .annotator-viewer div.share-button,
|
||||
.annotator-wrapper .annotator-viewer div.share-text-annotator {
|
||||
border-top: 0;
|
||||
padding: 0;
|
||||
background-size: 2em;
|
||||
margin-top: -0.2em;
|
||||
top: -0.5em;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Buttons */
|
||||
.share-container-annotator .share-facebook-annotator, .annotator-wrapper .share-facebook-annotator {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wDDBEyHq7FE8kAAAo8SURBVFjDtZhZjF1XlYa/tfY559atcs0uDxnsJN0iGAGJcIgYgkAgoEULCYH6oZtIIPGAExwgQYQExAsSCgmJEcIMfkCAQOEhQjSIILUYlAi6W93CYkg6jSUnHmJXYlelXNOtutPei4e9z1DBDlO40tW955x99vn3Wv//r7WPkD53f+0o9xzYH/8fedypyKggowgIgvHifgSwOGuwENaD+e49B66zu488xj0ffMWWcdz5pf/mvtteC8BdR373MhX3rpHC3ZQ7udo5yf5eAIMZPthGf+D/rzcMPw8h/ODeA69cuOurv+Vzt1wXx93+ue/yhbv+NYL76u/emzn36dmp4trpbQVFLiBCCAH+DgBFFDNjs+dZWOkPVzv9R4P3H7r31uuPfeLwUe49uB95oGd8rCXc+aWj79A8/8ZVO7ft2D6V2/qm5/yFHqsbA7FgLzpAA/JcmR4vbG6yIHfCyXObsrjcfUwGm2++9yOvWfz4oZ/GFH/0/kdnstb4t6/YOfZPV8y19dxS154+vyFDj6nEMS8C4S768cHYNpLZ1ZeNMVJk/P70il/t9O479OEbPgWgN+YQjFe2W7p/x1Qhz6307NSzHekPvIFJMOOv/foQ6PY9FowiE8bHcmYnc7ZPFWyfLJgez2nlYiudvjw1v44PQ9k103ICb7zt849cDpC96pMPagjh2onRbML7wNnFDbr9IU5VvP/ruRfMGA49r943y7V7J5gebzFSOPJM0FJ0Ag//51k5euyCBTN55rmu7Z4dkTyTKzc7g13A2UxCEMJwKs+02Oh5ubDSwzk1M5O/DVzg5rdfzQ37ZnAqiMQ8i2jKd5y+VSgD7yV3sLzWY26ysCLTzPobbYBsfem0TLa3q1mgNxjS63taRRD7G3ThA7z1hl3c+LJZREjgatWWx2BYMMLQE3Jhc3NAbxAEC+KHPd0GZGYiIQSCD4hA/K8vqL7ns1+im8frBrMTBfv3bUd1axK2gqvv9z5gPuAVsRAihhCvZmCEEEktwQgh8OdRr5RmSpeUcjcunxtl+1TrjxeXAJ4536GzOcQwLqz2EIyhDzgnBAsJT2AkRtASYkPF8MHzgr4sWsUyRqMOnQEqMDfVot1yiEgFysxQVR766Ql+9qtnyDPFMPwwUOSSMAgWDLOAmbEdyLwPeO8JPpqeDY2gniYHKyBCI2qNSEpVG0CN0ZGswbsa5PJ6nx/98gxFIYR+jIKFkKpV5KMFY+g9fui5HMhWlldZC+eZnRpnbNsoG70N1LVRFUQUESqwZkSDkKYQDTOwABDAdMvimrw7dmoFVRgMDQUChlOQZEkbfkCns8H5c4s8++wCP3kdZL1Bn/7yKheWlul0Njh54hmmJsZotVqMtEdotQpcluGcQ1URpxFZQmHA3p1jvHTvBN4MFWHv7rEt4MrfXdMjvO01l4EJpVb+6zdn+P/j5xgOBmQa2DEWWFpaYW2tAx+DTBBEY5rMB3rdPquAsAGiqDryPKNoFWR5Rp7n5LnDuQznFFXlql07+Je3XMXABzBwKpiFip8lyCt2jvGeHVdBzCqZUx574jRnzi4xPprTHskAcBrnZwmymC4BU0ARNJmpYCgGdHtDur1hg3OOzCmSDHj5pVOICEXmqpSXoMpIAjinuIuJTjTRSUCVZJ7QTRGkvFh+y3OJ+CUfq7yIYAgW4nFodDt/ucELgtbAkBQowEFWehgioIJo5FqwCFAaN5XVoFy5SAx+u108T/F11JoGf7Ha2W7lyerrIMRnKHQgqyYVSRFTDEVTlKBxk5EWU6pbUBF+8etnWVrtRy9V4Q37d3PT9bu3CEWAx598ju//7ASSyoQI/ObYAtvGisa8jYBIKRJqcCKS+JNsRiMfRQScqx5mCCqKKZw4u86Tp9dABOeE3XNjFcBmaZs/3+GHj5xExJJDGU6Moijw3leUEo38ZrlMMVobbQlUEzek5oikZcd0xWtqIE5xaakqgtOL13IVpciz1O6Xvhkrh2zhfbVdoh4tpd1ERVm6IVaHqG6TSjaNylFHlMqyLtGpSVNsITlHMn61inv1/JCRUlqSXysepOipVkClSeaqNRC0VJ3QeMAlFCsOJN4Vq3dATOO5FAjKRUgCWK64jE8ZalOtlZV8UbRpNw6HEBLX5E9GkGouEat3xpJAIpRGKQgYZFjTRrRSk9HkYDynjWMrF1G1WUq5yecS+6w6+pF/sclO9hV7oYo2iMACZIglbtQWUltODa4Cj2C4LaKqxxL5eokIxvMuRY8oDgGjTHHTYhQ2GzZTWklZcswaXGyAE3H1SqUGFR8oldIv3o4nCkDiXQ2y9ECpcJA4aLXC6vZOEgapFB1vcvG4nAgXsZc0cUlUppdUMaKIhZgU0/icZDOGmsSqkVyk8sFSkalJENmixgocDXCNWo026SCXDGAdAa04aCmSiCEiYpWrCPSTikOyiyyrH2xNw0wcrG6m4YvS4GhZq19AxXH+VJnNJ6HEBTrVmPVy07wGqhIwbwwGgZFWxthojg+YNNRbprxMawmuqjpVN6Rb9ykX9cG4mOi3rkq9DzA+VtBqZXT7ARWB14POTDqfu+HS8lqv125ldvncNgvBokuJWPlAMWl0Q7GkqUZfFIl1WZ0DyV5AxSW/pXI3UTUzoVU4u2xulOHQ6Gz0enk27MpdoK+ffjiM5SvHl1bWl9Y6A/5xzwRz022zgIGIGVaZeZN3qeuJxy42t0n565vG4nKf+cUe8ws95he6XFgbsLLua6NGMRMLJiIqtmf3NnbNtu3JM6tmvvfUbHZuvipOt95yYNfxjeu+7Mb2vPtV+2aDaibHTq/J4oWu9Qci0afURFRiqWpWmLLjcZRlc/tkwexklhpZwwg4heXVHmfPbxoEEQIigXauduXOEdm7u23zi5s8cXzBT8nxu985df8XP3D/mUEG8Kapb5/ztI6c2Che/j+Pu5fsu2Y8XP+SaetsBlntDGzgY5VGIneaZi44RGt1lwKxaq8cwBwWAjOTBTOTuZgFEwKtXGR6PEPFwvGnO3JqfkVm9MQPrmn970MfuP/MAMB9/Lb3cvsDR3nnayeeHm11n+l0s6tPPZftWFwe6MCbFFlmzjlxTsmcok5QdWSqqNO4cXKKU0WzyEOXuXisghNJv6DOyITEX2zQ98wvdjl2asWWlpY6O90T/76n+NVnHzj84DGAz9xyfUzxHQffz6HD3+TTB2/KO/zDqxcGe/75wmDnDV7a0yIuvv55XvNqUvYwjY5bU7skZRtgkN4UYLH3CxgSQowsZhaGwxYrZ2eypx+dcScfvu/wQ08B3HnwPdx3+Hu1H9x+8Ga+cPg7HLntSk5y42QvtHcGdMIHXKphYFX/0XzZljyNurczq984WP32oX4Zb2CCqpgKvUyHSy1WFj57+MebAHfc+m8c+sqDjbY1fe740Ps49OVvAXDngTfj3ax4b5hPXGpugSykM89/v9sc98clTxtl1amSuYFN9/6DT359AMCtH7yZrxz5TjX+DwV2mkY3fbDAAAAAAElFTkSuQmCC');
|
||||
}
|
||||
|
||||
|
||||
.share-container-annotator .share-twitter-annotator, .annotator-wrapper .share-twitter-annotator {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wDDBEyN+x3i6UAAAriSURBVFjDnZhrjF3XVcd/a53HvXfuzNieiY2d2q6dh0NJQkPACTVEhArlQwlIcflQoxZoSEIDLaqqCpCKQAgJhNRviEQkadqUNK4ixVTCFREWqRSJtrHSpqQJips0cZz4lbHH877nnsdefNj7nHvueJJSjrU955577t5r/9f6/9daW2hd9x+f48FbtvLp4/ORs6pvqrG1vpcwxp4oEF4SBRxY/VL7x2bNT+pbE8HK0kWq2QO3XJEB/PG3T/PAgfeNrcmf/OfblNMp/7x/G/cfnztQVfZbvUgOdmLdHYmIKIj5t6W1riAYIONWt63CEMT83bqvqEDKqlocVDxbVO6pK4bzX/+72z9g9z3zGg99+JqRgfc89w6P3LqNTz13/q+qyv50Vz+enUkjJiJFFUrzM8roJyCGrMMTWw/x6IHV9+afKhAJ5AYruePsoGShqI499KHtdwB87PN/zde/+DfIvd8+y8MHdnDfd85/tqjcP9w0k6ab0tgGpZOTqyXLhfMIyWjtMUPrZxugaHY5ovX/Fuzdlkbs7scmInJiKedCVr3w8IHtN4+5+J7/OrOzNI7um0o+uL2fMJeVvLZUoCIeKQEx706D8NwvIoBKCyHv1MsQa/bjRq4HwxmkCj87ndp0qvLduUGeZ8PPP3L7nn8kIE1ZVbf2Yvngtl7M0rDixGIOYRFnYCYMHcQq7JtK2D/b4Veu6PLzW1K2diMGlcOZYOFd1/rrxBrEzMzPGWLXBVMzZ5xYziUrjX1TaZojv/0HPWKA+JMPPaV5nl+7c6pDJNgry7kQEDHzrssqx1WTCXftmuK66YQ00sZp72Qlz74z4Ni5tYZIbfdYiN8WsyAYai2qLecV5waF7ZhIZEJtV/bot67m0K+fUHp9dVU5m6qwUlayWlTBnYYJOHPs6EXcfc0mbtzSIYlqHvvpt3Zifmf3JB+a7SLqN1SPmlpmXnpqjzhcg7ZHFFSF04NSRKCr1ndlPgUQqznMuSgSWCl9UDmxJsojlFtme+ycSABjvjB+nEOOMBM5rutAZMLH907xvfmM3NaTw28U87HpzBDUB5A4zI24vlpYTUaxIo8A1DknzlyIBz+5M4cz7+JI4de29bxxpXGqgL0pXN8xuiK8OPCzx6rcuLmDM2shbEGOWuwNsV2FEKpf98haszkXNCy2oOgEMfVGSpAWowJmujEAZwtjOhYuOT+RCsQCSxVMR/D+fsx/nHPEul5ehEQ8W4XgIQvRJy5IjoQMZH6TwdDYTDAzXCC+w9CW4rmWu0yENWeB4aPYd+H7/TNddkwk6+Wb0hknVwuOnl6hMIgDCK5B1k9kwWvWylZxZY7KjQuoqbUUf7RcYVCZjCUt17qf6cYN2usF+hdmuty1a4rH31jk6bOrJOLJgkmTo7w3vcFV8HV8frDGwuoq7x/m9OOI3DniKEICDU3G00E+0uNGNQbOiFq7Xp/xBJhQQ4GP791EqsK/nV5B1acoNaNwjtWyYi0vOb+WcWEtqxE0Lg1z5gYZy5Hy5tKAXhLTiyL6acxkHI+t5MZykL9OFpBgdAQSpTG2cH5DOdAR+LmOkIpxx/YJvn9pwKvLOVlZMigqhlXFUl5yYXPEwrAgc36lWEyIRYlEMbwol5SsFhWX8pxERxGfVTA0iMxQkVB+CU4gx8hNkGokM67JFrDijOcGjtv6EZs7MQkVp5bXAoNdcCtEIkQiTWjFiCAiQWSVSKVZfExxgcwZq27cx7ZBMbAByAjCRTMqZ0Qq7JxIiVUonQuqGJZDUJVm2VjFy4WG4klEUAl/xyji2ViYIBj/n6tyRiSjzQKoeO1x5lC1xkgRDS4ORnnAfPJV8YapEgJ5xOLc2WUy4jYsrcavzBm/3NcmF7+1WgCKqmHOUFGUkPxb4h4r6tFSQUMpNdqFjBWlpUGxgYGzMXT13Y2MRLi2I2xPfdS+tJjx0tIQVa/BiPeKiPeZiiIBmNjEPILBMK1jMoyoRZLCGaVbvzjcPKFsT/Un+9iM+WHJg6/Ns1A4UhWcRZi5pnJqRk0SqRGzkKWDkRoQbMNVGuTmxlB1VrcE7345M06tFbyxWvDV1xd4eWlIP45wzoViV3BApJ6AtU1jMTiyXAOL/T9tsbh0RuHGHRy/h0DXqJlBLMLz8wNeXMrZnES+plYF57xYB2LW0lVPpBKKH9FgkNbxF9i9HkFnFO1hYx3l5ZdIkJWEz+6b5ckDVwaxD0ZpWLMGRf2oAyb2VYtvDZsXtUZ0PK42ikEnxuncheJ2YxenYszESlfh6n7K396wlb98aY44xJRhKDbWnDUx6Br3hhhsejZ/FwemiQjTEZzJL2fxN+crSqveRR+FyoyZWPjYtoQ9HeEXt3S5aXOXHy4OUfM9ChKkxuqVPTiqoQtrS8uIyRCp8upyDsBNk8piaRQ2PhQjFSMRNhhGV2G5Mr5yNgeBXqzs7SdE7SyGjBBsJTCtMwfrvqyNLBw8e2EAwL6JmNlIGFa+EPhphplwsTDWqlCadWLi9Zpbx6GMzlO0tqgmS20Ywe0OeGFhyGJeYmZ8ZmdC5YyhM/KfYmTON5sTkTdwqXSYemNUW17DELFGPXQUbyNq1/Ii+MrixErBN88NEIHJCD63O+XqrhIjLJewWMBi+R6j8Gc7n/iZFBBKZ5xaK70466iyaAjbljEN/YcDEh0VDNKSgQQ4/PYKvUi4632TXNkx7r0y5VTmmC+Nwvnfv9sZkgA7OsJVvQjM+MHikFeWCyL1LYWI70uTEITGKAhjw5kKljvH7iSlNEhrMMXrUV1MPHZqlf9ZKfnCdZtIFa6p/fV/qm78HO8MK/7+R4tUNTHNUJQKx2wnxuEonBGZFy297QsHq24+eHuh8C3MVZMdnMkIahkxG4XjC0PuOn6Bx95a5fSgZKl0rJT2E8elvOLxt1Y49L0LPq2FJFCztwSunUopHFzK8tVN508uA8R/Nof95mDpRxdWs8HaVKf3gU2pLZWZrDlfhdDKvBLqNxXhqbMZXzudMREJm1INuTtUnWatHtsonXExr0gFtiSRb4iCW0V8Jb23n9hsGslLCxnJYOXkDV/+8zMNSfYc+8pzyWD5+RcWMgRk/0yXK7tx6OJ8b1yFhO7MmnjdnCidSMkcZAaZU4ZOyCyMCjLn68ipWElUqEK8VyEzIcK1/cRumE7lTFbaW4PC7fz+00eGbxRLY+nzU39032+8dvBzR+Jef+rmzR2b7cRSOONi6XNu7WaVdWKudYER+B8krOlxzXzfXZ/JON97Y0Yvgi2hy391eWivD0V2HHvsXyZf/s5f/NOT/3oGIPrdT/weP3zxv5m9fv+bNzz/jVcW9ty4/6RMbJofllIikkZ+54lqa8jYSFVJREgiz8REhUh8oo/D6UOkECNEXjqIEIaVcS4r7eWFzF1cXsl2Pf2lJ3pnX//iA48f/vEYte6+514efeRhbv39+/VXL5z4pYv77/joyp7rby07k7NeEmUcwaZEq8skHetlauRcOHypw8JcOB80C/eg5TDrzp1+Y8sPnjlW5sOnH3ziyTcB7rzzTo4ePTpy8SfvvpsvP/ooAJ/5yO2TMbZVRKYtiuNaRUZnN/Vp1egc0TY4l5bW0bA/h5HWM0Ewc47c0uTSan9m7kuPP5EDHDx4kCNHjlxewh06dIjDhw83n2/7w0+zTaoxpWuIKkJ9jC7vVU237tS1PpvRm5zkmRdf5uy3/r15a3p6mqWlpebz/wJ5Ut7CxANClQAAAABJRU5ErkJggg==');
|
||||
}
|
||||
|
||||
|
||||
.share-container-annotator .share-google-annotator, .annotator-wrapper .share-google-annotator {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AsJEzYNSj34jgAACUBJREFUWMO9mF1sHNUVx3/3zuxs1t7EEEOcDxJBGycCFBMaRzFSw1v5KN9BSA1QaEQfEBVtpJYWUKMQwUMlmhdo+oZQRVNCQoooaqAEAX0oUqkKIQ2IKNAmNiixieP4c2d3557Th70zmV2veaAVK408M75z7v98/c8519D8M/7S3PPX+RPAzO8smMnpurQCCIAQkJduumXDgsAurjvXtGakcxkHVt5JoElb6UYNrjjG5CX7MRLOiWKJUTZHddIVCtgAjaKCvHLwk0OP7/rbCY+nHubART+8+BvLf7ay9/fRxMR6bYBr+oUsZbq4loLU2u+slvq8zznVM4F1xTkBnh841nTOEM0WwKV3d3Pv9dfvvHrLW786+UU8GXoTFRSiB3p6ngrPjK53om2dW48qTMVKwUl7CwJV6pyeGsXKvDkBjgUJLphG2gaQcmFn+NPf/HzVB5seOvynEDAKEbB0QWXmWjdTAYO2i78kmmE6ViKnc1hQqZJwpnL2SwFOhAlSmkSNtkdoMJcuL94FvB56IPN6S6UlOjmJVmMwpq1uUqpQrSk6F0CUSiBMVCexLpkT4HSUQH1irhQ0GEXrHQuBcgqwEIuUqgbEWjAGVW/IHNbEKKGpEprqHFtbCqZO0RWwUpgTYOgsNSlhTM5RqlmcGAOTcSEASlmSnBQJ7iiXCcOQwFqstdggaNwbg7GWwEzS9f4tGGPntGAHlqv/vmJOcKqKAHdqD6KKikNEERXEOUSVJHFUKtMGCFMLGgO2ZC1REGCDAGstQRBgjWmAtRZjDNYW/2eyU1VC1QZYMagqTgQRiziHc6DOmoZP2nysIuAFZFqLNP6Xe/9VwbXeq2pjv/weWdC0ZKHmyJM2YFQVY8xXApl+mxmijcI6i3ubIigHKtXqS0ACiAgi7XkxCIImQMYYkiRpIolUtuT2ze8XzrJg7hJfYtpZM43RxUuWsLinhyBsFlWr1Tj0/vsZ+BRcX18fw8PDnDp1KnOlthgjM1ATwPyC3EcigjWN3FegVq2yatUqbtm0iVq1SpIkXLF2LatXrwbgnXfe4bPBQV599VVEpMmC09PTPPTww7y4bx8v7t2LtbbtvuotOhtgXhvvPhsEmXtcknDZ5Zfz6507eeaZZ3jl5ZcBcM6x44kn2LhxI6tXr2bH9u2g2gCQizdUqVQq1Gu1rHVpikWRBgafpLOSJM1UybtZBPVxVowifrx1KzYI+Ovbb2OMwRhDFEU8tm0blUqF7u5ufrJ1K7VaDRHBJQmJv+pJ0njnHPV6ncRfGUPkMGirBaXVzSJozgVGlcVLl7J8+XJEhLhSabjQWkSEIAx54+BBvnvDDazp68ticv3AAL29vagq1Timq6uLDQMDdJ13HgYICwX27d3LmdHRhlu9gWbHoKeOFJwYAz7+0lgqFAqUOjqIKxUuXLSIocFB8G4xxnDs2LEmzhQRuru7Wdnbi4iQJAmFQoFFPT04L7NYnEchDHHerXkvNgE0PjBFBIzBeAuKcxAEGBFmpqeZnJigWCyy9sorOX78eKMM+gSqxlXCMOTw4cPElQqlUon9+/bx/O7dAIyPj/PKgQPsef559vkkEecodXRk3Cot1GbzSZJaI13o0njwMTg4NMTRo0dRhRtuvJEgCDKNa7Uaa/rWMDg4xM4nnySKoixuy+UyneUy88tlAIpRxHz/XC6XMcY06nCbamVbB4I0KdKy4zw4EaFeq/HLRx9laGiQZcuW8dTTT3PxJZewsLubLffdx8qVvfzgnu83lUeXynAOp9oYeBScyDnZzmVGSb2orUStuRgUb03rY1OMAU81E+PjbLn3Xr61rp8VK5bznWuu4fY77kCc467Nm6lVqxm9pNUppZhCGPLcc8/xybFj56pQzq0iAh60eoKfTTOpVjkXZ1p6zUSEf/7jXf64fz9HjhxBnBDHVTo6O86FR/qdl+lECAsFDr7+Ov/+9NMsIbKk8PLTPWltFkzOeprrLFL3ZIA9t1WrVapxzOEPPuDs2Big7NjxOH19fcSVCurcOdemijs3S5a0yk9jvjWLUwaXtDQZg/X0ob7UGWOYiWN6enq49rrruGLtWlYsX4ECURRx/sKFbHtsB7979lleeGEPxWKxqa5KS5VKAWquWcgbaZaLNdedaIsLnHOU5s3jF488wt4X93PRRRfx2127uO22W7lqw3o2b97M6dNfEASWu++5h741fTifmc5Xj6b71MJetnoXp9mcKhV4kAustUu6Fiz4HsZks4zJdTIiwpM7d7Lx2xt54P77eWHPHmZmZigVi3R2djI2NsYbBw/S37+eRYsuZGzsLIfee6+5Cc1VilZKaW2KnXOnJiYnX7atRN1KMapKtVrlpptvZt26fl77y2t8+OERSqUShgZdJM5hjGF0dJQdj20nDAt0dXU1U4m/T3LWzHspX0GkXQySxqCnCONcVmdr9Tpr+vqI45gkSXDONapAztqpkh9//DGqyokTx3FJ0tShz9X3Scu7tlmsuRjUFm4yxvCvw4ep1Wps2DDABd0XEMexH3BcZoFKHDMwcBUjIyO89eabmfXSmJPc2jz9tLo39WT7maSl2IsIYRjyh927+eijj6jX6zy1axfr+vspFAqEYYi1lqhQ4NLLLuNHDz7I9m3bOHHiRLMCaZLkQLpcAmaVJ0fSqVdCYFkQBFcu6el5SVUx6YjpKSftijs6Orh10+30r+vnm70rOTs2xsjICFNTU0xNTjE+fpYDB/7M558NEUXFpjmn7RSXb2bzVNNQ4NDJ4eEtswCKL2nGx1d270th2nYZYymV5iG+UQBwviFtd3Ki7UDmO+r8mNEAeejk8PCWsN0BEKqotdkJkslNcelAZIyhVqs2Wbjd7Puls3BuBsmefbvXOtWpc66ayTD+cCaXQKblyNVo7tzGrzW+uWidsZuUz2d0m7+5mTsBNPTrHTAuqiPAItPcQWSdjvElsOnYtY07TZsBPA+u9d7kvJACrdfrhwAN0uM3YL6InC1G0Xpoc/jZEgKznluG/Vnv53D/LOWMwYkcHT1z5llV/Tw9NJ8PLAZ6wyDoK5fLA9baC77mQ3Q1IHG1eqwSx++KyIfAf1IARWCBB7kM6AbKQOFrOu1P60QVGAdGgM+A0yZXUQpApwfW6UEHc4XU//ln/MSRADEwBUwC8X8BTYvqIryh+pIAAAAASUVORK5CYII=');
|
||||
}
|
||||
|
||||
|
||||
.share-container-annotator .share-email-annotator, .annotator-wrapper .share-email-annotator {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAABIUExURf///7KysrKyss/Pz9DQ0NHR0dLS0u7u7vDw8PHx8fLy8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///37mbPQAAAACdFJOUwCWb//7SQAAAQNJREFUSMft1M2SgyAQRtHkC0RtbP6V93/TWZikFDuQ2c7krrCKU1gKXC7f/lNX9LvuAVB6AUdw78y/V2CEXltpjEcwmabQMNMR0GwbQsPOVAF2AXqR0wiOK2DYh/RGaKTg2VTA+pgXUWgsOXorghUq1ymsDVBOQqE0QYFK+xRKBxyFQumCvVAoH4ACFbe2+f0VnkKhfLICnmsoPJ46X2l7q1u4PUYdgNdxeY2aQDp4b/40+5AyxM2NLGw+YhcisrhbM+J5e9NsPWLKUinCnw7QZBg+hCgVggfXR3QksHVezlkGVZfAADIzs5Ving1hqO6lYZyIjBzRNA7He+nXV+W3v98P7gg+L5LCf08AAAAASUVORK5CYII=');
|
||||
}
|
||||
|
||||
.share-container-annotator .share-button-annotator, .annotator-wrapper.share-button-annotator {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAvCAMAAABE+WOeAAAAA3NCSVQICAjb4U/gAAAATlBMVEXMzMzZ2dn////r6+vPz8/n5+f5+fnl5eXT09P19fXz8/Pg4ODX19f7+/vR0dHp6enu7u7d3d339/fj4+PV1dX////b29vt7e3h4eHx8fHJkyUPAAAAGnRSTlP//wD//////////////////////////////zDtagYAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAedEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzUuMasfSOsAAAAVdEVYdENyZWF0aW9uIFRpbWUAOC8xNi8xM7KZeroAAAFnSURBVEiJrZaNbsMgDIS9jpCQ0dBoVaW9/4vOQHD4OVIh9aRKLf0UG9scoduYqF7Qs1UUpeys3/Buo1Kbu+BnQpo7/KogznmtiMcPr0MIv1/gRHvNLy0zcXH0dPxYSh483cR/TBmBerlPKYMUYT75FWQsndJpZRUeFTIr4SGVeFjJlg8ZUb5wnU94Bn8cwr/u9X5ZLvD1iHn9SjYmW908r1t6+eM0bNGvlCSB3e4MfqOovGO62XqRO6U702SZl+LH+E9uiwHTFKSYT9+NbNH1DgJXVHiZl/urS+c86s8VD/r/UX40H9mvgZ06+VQ8qWfXV2L9pb+xX767TcuTLJifn/44hPlp9mdNMfS5NJz/p/HzCcZ5652vBzwux/kCDVKnYeYRLvxBjm+2veQPyH/AeIj/IH8D/OlvIKN2nDL/BP7c2G3hz8D/Kzuv/B9FyPvV3C/D99fw/dgN0bt/vcbud6+x94e3+gd13Qxqz2VnfwAAAABJRU5ErkJggg==');
|
||||
}
|
||||
|
||||
|
||||
/* Api */
|
||||
.annotator-wrapper .annotator-hl.api {
|
||||
background:rgba(0, 190, 99, 0.3);
|
||||
}
|
||||
97
common/static/css/vendor/ova/tags-annotator.css
vendored
@@ -1,97 +0,0 @@
|
||||
/* Editor */
|
||||
li.token-input-token {
|
||||
overflow: hidden;
|
||||
height: auto !important;
|
||||
margin: 3px;
|
||||
padding: 1px 3px;
|
||||
background-color: #eff2f7;
|
||||
color: #000;
|
||||
cursor: default;
|
||||
border: 1px solid #ccd5e4;
|
||||
font-size: 11px;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
li.token-input-token p {
|
||||
display: inline;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li.token-input-token span {
|
||||
color: #a6b3cf;
|
||||
margin-left: 5px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
li.token-input-selected-token {
|
||||
background-color: #5670a6;
|
||||
border: 1px solid #3b5998;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
li.token-input-input-token {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
div.token-input-dropdown {
|
||||
position: absolute;
|
||||
width: 400px;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
border-left: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
cursor: default;
|
||||
font-size: 11px;
|
||||
font-family: Verdana;
|
||||
z-index: 1000000000;
|
||||
}
|
||||
|
||||
div.token-input-dropdown p {
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
div.token-input-dropdown ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.token-input-dropdown ul li {
|
||||
background-color: #fff;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
div.token-input-dropdown ul li.token-input-dropdown-item {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
div.token-input-dropdown ul li.token-input-dropdown-item2 {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
div.token-input-dropdown ul li em {
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
div.token-input-dropdown ul li.token-input-selected-dropdown-item {
|
||||
background-color: #3b5998;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.token-input-list{
|
||||
padding:0px;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>
|
||||
This is a custom SVG font generated by IcoMoon.
|
||||
<iconset grid="16"></iconset>
|
||||
</metadata>
|
||||
<defs>
|
||||
<font id="VideoJS" horiz-adv-x="512" >
|
||||
<font-face units-per-em="512" ascent="480" descent="-32" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph class="hidden" unicode="" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
|
||||
<glyph unicode="" d="M 64,416L 224,416L 224,32L 64,32zM 288,416L 448,416L 448,32L 288,32z" data-tags="pause, media control, audio" />
|
||||
<glyph unicode="" d="M 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" data-tags="volume-mute, speaker, media control, audio, mute" />
|
||||
<glyph unicode="" d="M 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
|
||||
c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
|
||||
c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" data-tags="volume-low, speaker, media control, audio" />
|
||||
<glyph unicode="" d="M 359.765,64.235c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.372-9.372,24.568,0,33.941
|
||||
c 65.503,65.503, 65.503,172.085,0,237.588c-9.372,9.373-9.372,24.569,0,33.941c 9.372,9.371, 24.569,9.372, 33.941,0
|
||||
C 417.532,335.938, 440,281.696, 440,224c0-57.695-22.468-111.938-63.265-152.735C 372.049,66.578, 365.907,64.235, 359.765,64.235zM 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
|
||||
c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
|
||||
c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" data-tags="volume-medium, speaker, media control, audio" />
|
||||
<glyph unicode="" d="M 445.020,18.98c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.373-9.372,24.568,0,33.941
|
||||
C 471.868,103.771, 496.001,162.030, 496.001,224c0,61.969-24.133,120.229-67.952,164.049c-9.372,9.373-9.372,24.569,0,33.941
|
||||
c 9.372,9.372, 24.569,9.372, 33.941,0c 52.885-52.886, 82.011-123.2, 82.011-197.99c0-74.791-29.126-145.104-82.011-197.99
|
||||
C 457.304,21.323, 451.162,18.98, 445.020,18.98zM 359.765,64.235c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.372-9.372,24.568,0,33.941
|
||||
c 65.503,65.503, 65.503,172.085,0,237.588c-9.372,9.373-9.372,24.569,0,33.941c 9.372,9.371, 24.569,9.372, 33.941,0
|
||||
C 417.532,335.938, 440,281.696, 440,224c0-57.695-22.468-111.938-63.265-152.735C 372.049,66.578, 365.907,64.235, 359.765,64.235zM 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
|
||||
c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
|
||||
c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" horiz-adv-x="544" data-tags="volume-high, speaker, media control, audio" />
|
||||
<glyph unicode="" d="M 256,480L 96,224L 256-32L 416,224 z" data-tags="diamonds, bet, game, gamble, cards" />
|
||||
<glyph unicode="" d="M 0,480 L 687.158,480 L 687.158-35.207 L 0-35.207 L 0,480 z M 622.731,224.638 C 621.878,314.664 618.46,353.922 597.131,381.656 C 593.291,387.629 586.038,391.042 580.065,395.304 C 559.158,410.669 460.593,416.211 346.247,416.211 C 231.896,416.211 128.642,410.669 108.162,395.304 C 101.762,391.042 94.504,387.629 90.242,381.656 C 69.331,353.922 66.349,314.664 65.069,224.638 C 66.349,134.607 69.331,95.353 90.242,67.62 C 94.504,61.22 101.762,58.233 108.162,53.967 C 128.642,38.18 231.896,33.060 346.247,32.207 C 460.593,33.060 559.158,38.18 580.065,53.967 C 586.038,58.233 593.291,61.22 597.131,67.62 C 618.46,95.353 621.878,134.607 622.731,224.638 z M 331.179,247.952 C 325.389,318.401 287.924,359.905 220.901,359.905 C 159.672,359.905 111.54,304.689 111.54,215.965 C 111.54,126.859 155.405,71.267 227.907,71.267 C 285.79,71.267 326.306,113.916 332.701,184.742 L 263.55,184.742 C 260.81,158.468 249.843,138.285 226.69,138.285 C 190.136,138.285 183.435,174.462 183.435,212.92 C 183.435,265.854 198.665,292.886 223.951,292.886 C 246.492,292.886 260.81,276.511 262.939,247.952 L 331.179,247.952 z M 570.013,247.952 C 564.228,318.401 526.758,359.905 459.74,359.905 C 398.507,359.905 350.379,304.689 350.379,215.965 C 350.379,126.859 394.244,71.267 466.746,71.267 C 524.625,71.267 565.14,113.916 571.536,184.742 L 502.384,184.742 C 499.649,158.468 488.682,138.285 465.529,138.285 C 428.971,138.285 422.27,174.462 422.27,212.92 C 422.27,265.854 437.504,292.886 462.785,292.886 C 485.327,292.886 499.649,276.511 501.778,247.952 L 570.013,247.952 z " horiz-adv-x="687.158" data-tags="Closed_captioning_symbol" />
|
||||
<glyph unicode="" d="M 64,416L 448,416L 448,32L 64,32z" data-tags="stop, media control, audio, square" />
|
||||
<glyph unicode="" d="M 192,416A64,64 12780 1 1 320,416A64,64 12780 1 1 192,416zM 327.765,359.765A64,64 12780 1 1 455.765,359.765A64,64 12780 1 1 327.765,359.765zM 416,224A32,32 12780 1 1 480,224A32,32 12780 1 1 416,224zM 359.765,88.235A32,32 12780 1 1 423.765,88.23500000000001A32,32 12780 1 1 359.765,88.23500000000001zM 224.001,32A32,32 12780 1 1 288.001,32A32,32 12780 1 1 224.001,32zM 88.236,88.235A32,32 12780 1 1 152.236,88.23500000000001A32,32 12780 1 1 88.236,88.23500000000001zM 72.236,359.765A48,48 12780 1 1 168.236,359.765A48,48 12780 1 1 72.236,359.765zM 28,224A36,36 12780 1 1 100,224A36,36 12780 1 1 28,224z" data-tags="spinner, loading, busy, wait, wheel" />
|
||||
<glyph unicode="" d="M 224,192 L 224-16 L 144,64 L 48-32 L 0,16 L 96,112 L 16,192 ZM 512,432 L 416,336 L 496,256 L 288,256 L 288,464 L 368,384 L 464,480 Z" data-tags="contract, minimize, shrink, collapse" />
|
||||
<glyph unicode="" d="M 256,448 C 397.385,448 512,354.875 512,240 C 512,125.124 397.385,32 256,32 C 242.422,32 229.095,32.867 216.088,34.522 C 161.099-20.467 95.463-30.328 32-31.776 L 32-18.318 C 66.268-1.529 96,29.052 96,64 C 96,68.877 95.621,73.665 94.918,78.348 C 37.020,116.48 0,174.725 0,240 C 0,354.875 114.615,448 256,448 Z" data-tags="bubble, comment, chat, talk" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 256,352
|
||||
c 70.692,0, 128-57.308, 128-128s-57.308-128-128-128s-128,57.308-128,128S 185.308,352, 256,352z M 408.735,71.265
|
||||
C 367.938,30.468, 313.695,8, 256,8c-57.696,0-111.938,22.468-152.735,63.265C 62.468,112.062, 40,166.304, 40,224
|
||||
c0,57.695, 22.468,111.938, 63.265,152.735l 33.941-33.941c0,0,0,0,0,0c-65.503-65.503-65.503-172.085,0-237.588
|
||||
C 168.937,73.475, 211.125,56, 256,56c 44.874,0, 87.062,17.475, 118.794,49.206c 65.503,65.503, 65.503,172.084,0,237.588l 33.941,33.941
|
||||
C 449.532,335.938, 472,281.695, 472,224C 472,166.304, 449.532,112.062, 408.735,71.265z" data-tags="spinner, loading, busy, wait, wheel" />
|
||||
<glyph unicode="" d="M 512,224c-0.639,33.431-7.892,66.758-21.288,97.231c-13.352,30.5-32.731,58.129-56.521,80.96
|
||||
c-23.776,22.848-51.972,40.91-82.492,52.826C 321.197,466.979, 288.401,472.693, 256,472c-32.405-0.641-64.666-7.687-94.167-20.678
|
||||
c-29.524-12.948-56.271-31.735-78.367-54.788c-22.112-23.041-39.58-50.354-51.093-79.899C 20.816,287.104, 15.309,255.375, 16,224
|
||||
c 0.643-31.38, 7.482-62.574, 20.067-91.103c 12.544-28.55, 30.738-54.414, 53.055-75.774c 22.305-21.377, 48.736-38.252, 77.307-49.36
|
||||
C 194.988-3.389, 225.652-8.688, 256-8c 30.354,0.645, 60.481,7.277, 88.038,19.457c 27.575,12.141, 52.558,29.74, 73.183,51.322
|
||||
c 20.641,21.57, 36.922,47.118, 47.627,74.715c 6.517,16.729, 10.94,34.2, 13.271,51.899c 0.623-0.036, 1.249-0.060, 1.881-0.060
|
||||
c 17.673,0, 32,14.326, 32,32c0,0.898-0.047,1.786-0.119,2.666L 512,223.999 z M 461.153,139.026c-11.736-26.601-28.742-50.7-49.589-70.59
|
||||
c-20.835-19.905-45.5-35.593-72.122-45.895C 312.828,12.202, 284.297,7.315, 256,8c-28.302,0.649-56.298,6.868-81.91,18.237
|
||||
c-25.625,11.333-48.842,27.745-67.997,47.856c-19.169,20.099-34.264,43.882-44.161,69.529C 51.997,169.264, 47.318,196.729, 48,224
|
||||
c 0.651,27.276, 6.664,54.206, 17.627,78.845c 10.929,24.65, 26.749,46.985, 46.123,65.405c 19.365,18.434, 42.265,32.935, 66.937,42.428
|
||||
C 203.356,420.208, 229.755,424.681, 256,424c 26.25-0.653, 52.114-6.459, 75.781-17.017c 23.676-10.525, 45.128-25.751, 62.812-44.391
|
||||
c 17.698-18.629, 31.605-40.647, 40.695-64.344C 444.412,274.552, 448.679,249.219, 448,224l 0.119,0 c-0.072-0.88-0.119-1.768-0.119-2.666
|
||||
c0-16.506, 12.496-30.087, 28.543-31.812C 473.431,172.111, 468.278,155.113, 461.153,139.026z" data-tags="spinner, loading, busy, wait, wheel" />
|
||||
<glyph unicode="" d="M 256,480 C 116.626,480 3.271,368.619 0.076,230.013 C 3.036,350.945 94.992,448 208,448 C 322.875,448 416,347.712 416,224 C 416,197.49 437.49,176 464,176 C 490.51,176 512,197.49 512,224 C 512,365.385 397.385,480 256,480 ZM 256-32 C 395.374-32 508.729,79.381 511.924,217.987 C 508.964,97.055 417.008,0 304,0 C 189.125,0 96,100.288 96,224 C 96,250.51 74.51,272 48,272 C 21.49,272 0,250.51 0,224 C 0,82.615 114.615-32 256-32 Z" data-tags="spinner, loading, busy, wait, wheel" />
|
||||
<glyph unicode="" d="M 432,128c-22.58,0-42.96-9.369-57.506-24.415L 158.992,211.336C 159.649,215.462, 160,219.689, 160,224
|
||||
s-0.351,8.538-1.008,12.663l 215.502,107.751C 389.040,329.369, 409.42,320, 432,320c 44.183,0, 80,35.817, 80,80S 476.183,480, 432,480
|
||||
s-80-35.817-80-80c0-4.311, 0.352-8.538, 1.008-12.663L 137.506,279.585C 122.96,294.63, 102.58,304, 80,304c-44.183,0-80-35.818-80-80
|
||||
c0-44.184, 35.817-80, 80-80c 22.58,0, 42.96,9.369, 57.506,24.414l 215.502-107.751C 352.352,56.538, 352,52.311, 352,48
|
||||
c0-44.184, 35.817-80, 80-80s 80,35.816, 80,80C 512,92.182, 476.183,128, 432,128z" data-tags="share, social" />
|
||||
<glyph unicode="" d="M 96,416L 416,224L 96,32 z" data-tags="play, media control, audio" />
|
||||
<glyph unicode="" d="M 512,480 L 512,272 L 432,352 L 336,256 L 288,304 L 384,400 L 304,480 ZM 224,144 L 128,48 L 208-32 L 0-32 L 0,176 L 80,96 L 176,192 Z" data-tags="expand, enlarge, maximize, fullscreen" />
|
||||
<glyph unicode=" " horiz-adv-x="256" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 10 KiB |
BIN
common/static/css/vendor/ova/video-js.fw.png
vendored
|
Before Width: | Height: | Size: 3.9 KiB |
949
common/static/css/vendor/ova/video-js.less
vendored
@@ -1,949 +0,0 @@
|
||||
/*!
|
||||
Video.js Default Styles (http://videojs.com)
|
||||
Version GENERATED_AT_BUILD
|
||||
Create your own skin at http://designer.videojs.com
|
||||
*/
|
||||
|
||||
// To customize the player skin, change the values of the variables or edit the
|
||||
// CSS below.
|
||||
// (This file uses LESS. Learn more at http://lesscss.org/)
|
||||
|
||||
// The base font size controls the size of everything, not just text. All
|
||||
// diminensions use em-based sizes so that the scale along with the font size.
|
||||
// Try increasing it to 20px and see what happens.
|
||||
@base-font-size: 10px;
|
||||
@touch-device-font-size: 15px;
|
||||
|
||||
// The main font color controls the color of the text and the icons (font icons)
|
||||
@main-font-color: #CCCCCC; // e.g. rgb(255, 255, 255) or #ffffff
|
||||
|
||||
// The default color of control backgrounds is mostly black but with a little
|
||||
// bit of blue so it can still be seen on all black video frames, which are
|
||||
// common.
|
||||
@control-bg-color: #07141E; // e.g. rgb(255, 255, 255) or #ffffff
|
||||
@control-bg-alpha: 0.7; // 1.0 = 100% opacity, 0.0 = 0% opacity
|
||||
|
||||
// The slider bar color is used for the progress bar and the volume bar
|
||||
@slider-bar-color: #66A8CC; // e.g. rgb(255, 255, 255) or #ffffff
|
||||
// The background of the progress bar and volume bar have a lined pattern that
|
||||
// is created from a base64 encoded image. You can generate your own pattern at
|
||||
// http://www.patternify.com/ then replace the value in the quotes with your own
|
||||
@slider-bar-pattern: ~'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAP0lEQVQIHWWMAQoAIAgDR/QJ/Ub//04+w7ZICBwcOg5FZi5iBB82AGzixEglJrd4TVK5XUJpskSTEvpdFzX9AB2pGziSQcvAAAAAAElFTkSuQmCC';
|
||||
// The color of the slider background
|
||||
@slider-background-color: #333333;
|
||||
@slider-background-alpha: 0.9; // 1.0 = 100% opacity, 0.0 = 0% opacity
|
||||
|
||||
// The "Big Play Button" is the play button that shows before the video plays.
|
||||
// To center it set the align values to center and middle. The typical location
|
||||
// of the button is the center, but there is trend towards moving it to a corner
|
||||
// where it gets out of the way of valuable content in the poster image.
|
||||
@big-play-align: left; // left, center, or right
|
||||
@big-play-vertical-align: top; // top, middle, or bottom
|
||||
// The button colors match the control colors by default but you can customize
|
||||
// them by replace the variables (@control-bg-color) with your own color values.
|
||||
@big-play-bg-color: @control-bg-color;
|
||||
@big-play-bg-alpha: @control-bg-alpha;
|
||||
// The font size is what makes the big play button, big. All width/height values
|
||||
// use ems, which are a multiple of the font size.
|
||||
// If the @base-font-size is 10px, then 3em equals 30px.
|
||||
@big-play-font-size: 3em;
|
||||
// Now that font size is set, the following em values will be a multiple of the
|
||||
// new font size. If @big-play-font-size is 3em (30px), then setting the any of
|
||||
// the following values to 2em would equal 60px. 2 * font-size
|
||||
@big-play-margin: 0.5em;
|
||||
@big-play-width: 4em;
|
||||
@big-play-height: 2.6em;
|
||||
@big-play-border-radius: 0.8em;
|
||||
@big-play-border-width: 0.1em;
|
||||
@big-play-border-color: #3b4249;
|
||||
|
||||
/* SKIN
|
||||
================================================================================
|
||||
The main class name for all skin-specific styles. To make your own skin,
|
||||
replace all occurances of 'vjs-default-skin' with a new name. Then add your new
|
||||
skin name to your video tag instead of the default skin.
|
||||
e.g. <video class="video-js my-skin-name">
|
||||
*/
|
||||
.vjs-default-skin {
|
||||
color: @main-font-color;
|
||||
}
|
||||
|
||||
/* Custom Icon Font
|
||||
--------------------------------------------------------------------------------
|
||||
The control icons are from a custom font. Each icon corresponds to a character
|
||||
(e.g. "\e001"). Font icons allow for easy scaling and coloring of icons.
|
||||
*/
|
||||
@font-face{
|
||||
font-family: 'VideoJS';
|
||||
src: url('font/vjs.eot');
|
||||
src: url('font/vjs.eot?#iefix') format('embedded-opentype'),
|
||||
url('font/vjs.woff') format('woff'),
|
||||
url('font/vjs.ttf') format('truetype');
|
||||
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
// Icon font character values
|
||||
@play-icon: "\e001";
|
||||
@pause-icon: "\e002";
|
||||
@volume-muted-icon: "\e003";
|
||||
@volume-low-icon: "\e004";
|
||||
@volume-mid-icon: "\e005";
|
||||
@volume-high-icon: "\e006";
|
||||
@fullscreen-enter-icon: "\e000";
|
||||
@fullscreen-exit-icon: "\e00b";
|
||||
@square-icon: "\e009";
|
||||
@spinner-icon: "\e00a";
|
||||
@spinner2-icon: "\e00d";
|
||||
@spinner3-icon: "\e01e";
|
||||
@spinner4-icon: "\e01f";
|
||||
@subtitles-icon: "\e00c";
|
||||
@captions-icon: "\e008";
|
||||
@share-icon: "\e00e";
|
||||
|
||||
/* Base UI Component Classes
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Slider - used for Volume bar and Seek bar */
|
||||
.vjs-default-skin .vjs-slider {
|
||||
/* Replace browser focus hightlight with handle highlight *///
|
||||
outline: 0;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
|
||||
.background-color-with-alpha(@slider-background-color, @slider-background-alpha);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-slider:focus {
|
||||
.box-shadow(0 0 2em #fff);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-slider-handle {
|
||||
position: absolute;
|
||||
/* Needed for IE6 *///
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-slider-handle:before {
|
||||
content: @square-icon;
|
||||
font-family: VideoJS;
|
||||
font-size: 1em;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
text-shadow: 0em 0em 1em #fff;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
/* Rotate the square icon to make a diamond *///
|
||||
.transform(rotate(-45deg));
|
||||
}
|
||||
|
||||
/* Control Bar
|
||||
--------------------------------------------------------------------------------
|
||||
The default control bar that is a container for most of the controls.
|
||||
*/
|
||||
.vjs-default-skin .vjs-control-bar {
|
||||
/* Start hidden *///
|
||||
display: none;
|
||||
position: absolute;
|
||||
/* Place control bar at the bottom of the player box/video.
|
||||
If you want more margin below the control bar, add more height. *///
|
||||
bottom: 0;
|
||||
/* Use left/right to stretch to 100% width of player div *///
|
||||
left: 0;
|
||||
right: 0;
|
||||
/* Height includes any margin you want above or below control items *///
|
||||
height: 3.0em;
|
||||
|
||||
.background-color-with-alpha(@control-bg-color, @control-bg-alpha);
|
||||
}
|
||||
|
||||
/* Show the control bar only once the video has started playing */
|
||||
.vjs-default-skin.vjs-has-started .vjs-control-bar {
|
||||
display: block;
|
||||
/* Visibility needed to make sure things hide in older browsers too. */
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
|
||||
@trans: visibility 0.1s, opacity 0.1s; // Var needed because of comma
|
||||
.transition(@trans);
|
||||
}
|
||||
|
||||
/* Hide the control bar when the video is playing and the user is inactive */
|
||||
.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
||||
@trans: visibility 1.0s, opacity 1.0s;
|
||||
.transition(@trans);
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-controls-disabled .vjs-control-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-using-native-controls .vjs-control-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* IE8 is flakey with fonts, and you have to change the actual content to force
|
||||
fonts to show/hide properly.
|
||||
- "\9" IE8 hack didn't work for this
|
||||
- Found in XP IE8 from http://modern.ie. Does not show up in "IE8 mode" in IE9
|
||||
*/
|
||||
@ie8screen: ~"\0screen";
|
||||
.vjs-default-skin.vjs-user-inactive.vjs-playing .vjs-control-bar :before {
|
||||
@media @ie8screen { content: ""; }
|
||||
}
|
||||
|
||||
/* General styles for individual controls. */
|
||||
.vjs-default-skin .vjs-control {
|
||||
outline: none;
|
||||
position: relative;
|
||||
float: left;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 3.0em;
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
/* FontAwsome button icons */
|
||||
.vjs-default-skin .vjs-control:before {
|
||||
font-family: VideoJS;
|
||||
font-size: 1.5em;
|
||||
line-height: 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
/* Replacement for focus outline */
|
||||
.vjs-default-skin .vjs-control:focus:before,
|
||||
.vjs-default-skin .vjs-control:hover:before {
|
||||
text-shadow: 0em 0em 1em rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-control:focus {
|
||||
/* outline: 0; *///
|
||||
/* keyboard-only users cannot see the focus on several of the UI elements when
|
||||
this is set to 0 */
|
||||
}
|
||||
|
||||
/* Hide control text visually, but have it available for screenreaders */
|
||||
.vjs-default-skin .vjs-control-text {
|
||||
.hide-visually;
|
||||
}
|
||||
|
||||
/* Play/Pause
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-default-skin .vjs-play-control {
|
||||
width: 5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.vjs-default-skin .vjs-play-control:before {
|
||||
content: @play-icon;
|
||||
}
|
||||
.vjs-default-skin.vjs-playing .vjs-play-control:before {
|
||||
content: @pause-icon;
|
||||
}
|
||||
|
||||
/* Volume/Mute
|
||||
-------------------------------------------------------------------------------- */
|
||||
.vjs-default-skin .vjs-mute-control,
|
||||
.vjs-default-skin .vjs-volume-menu-button {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
}
|
||||
.vjs-default-skin .vjs-mute-control:before,
|
||||
.vjs-default-skin .vjs-volume-menu-button:before {
|
||||
content: @volume-high-icon;
|
||||
}
|
||||
.vjs-default-skin .vjs-mute-control.vjs-vol-0:before,
|
||||
.vjs-default-skin .vjs-volume-menu-button.vjs-vol-0:before {
|
||||
content: @volume-muted-icon;
|
||||
}
|
||||
.vjs-default-skin .vjs-mute-control.vjs-vol-1:before,
|
||||
.vjs-default-skin .vjs-volume-menu-button.vjs-vol-1:before {
|
||||
content: @volume-low-icon;
|
||||
}
|
||||
.vjs-default-skin .vjs-mute-control.vjs-vol-2:before,
|
||||
.vjs-default-skin .vjs-volume-menu-button.vjs-vol-2:before {
|
||||
content: @volume-mid-icon;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-volume-control {
|
||||
width: 5em;
|
||||
float: right;
|
||||
}
|
||||
.vjs-default-skin .vjs-volume-bar {
|
||||
width: 5em;
|
||||
height: 0.6em;
|
||||
margin: 1.1em auto 0;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-volume-menu-button .vjs-menu-content {
|
||||
height: 2.9em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-volume-level {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 0.5em;
|
||||
|
||||
background: @slider-bar-color
|
||||
url(@slider-bar-pattern)
|
||||
-50% 0 repeat;
|
||||
}
|
||||
.vjs-default-skin .vjs-volume-bar .vjs-volume-handle {
|
||||
width: 0.5em;
|
||||
height: 0.5em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-volume-handle:before {
|
||||
font-size: 0.9em;
|
||||
top: -0.2em;
|
||||
left: -0.2em;
|
||||
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-volume-menu-button .vjs-menu .vjs-menu-content {
|
||||
width: 6em;
|
||||
left: -4em;
|
||||
}
|
||||
|
||||
/* Progress
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-default-skin .vjs-progress-control {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: auto;
|
||||
font-size: 0.3em;
|
||||
height: 1em;
|
||||
/* Set above the rest of the controls. *///
|
||||
top: -1em;
|
||||
|
||||
/* Shrink the bar slower than it grows. *///
|
||||
.transition(all 0.4s);
|
||||
}
|
||||
|
||||
/* On hover, make the progress bar grow to something that's more clickable.
|
||||
This simply changes the overall font for the progress bar, and this
|
||||
updates both the em-based widths and heights, as wells as the icon font */
|
||||
.vjs-default-skin:hover .vjs-progress-control {
|
||||
font-size: .9em;
|
||||
|
||||
/* Even though we're not changing the top/height, we need to include them in
|
||||
the transition so they're handled correctly. */
|
||||
.transition(all 0.2s);
|
||||
}
|
||||
|
||||
/* Box containing play and load progresses. Also acts as seek scrubber. */
|
||||
.vjs-default-skin .vjs-progress-holder {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Progress Bars */
|
||||
.vjs-default-skin .vjs-progress-holder .vjs-play-progress,
|
||||
.vjs-default-skin .vjs-progress-holder .vjs-load-progress {
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
/* Needed for IE6 *///
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-play-progress {
|
||||
/*
|
||||
Using a data URI to create the white diagonal lines with a transparent
|
||||
background. Surprisingly works in IE8.
|
||||
Created using http://www.patternify.com
|
||||
Changing the first color value will change the bar color.
|
||||
Also using a paralax effect to make the lines move backwards.
|
||||
The -50% left position makes that happen.
|
||||
*/
|
||||
background: @slider-bar-color
|
||||
url(@slider-bar-pattern)
|
||||
-50% 0 repeat;
|
||||
}
|
||||
.vjs-default-skin .vjs-load-progress {
|
||||
background: rgb(100, 100, 100) /* IE8- Fallback */;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-seek-handle {
|
||||
width: 1.5em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-seek-handle:before {
|
||||
padding-top: 0.1em /* Minor adjustment */;
|
||||
}
|
||||
|
||||
/* Time Display
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-default-skin .vjs-time-controls {
|
||||
font-size: 1em;
|
||||
/* Align vertically by making the line height the same as the control bar *///
|
||||
line-height: 3em;
|
||||
}
|
||||
.vjs-default-skin .vjs-current-time { float: left; }
|
||||
.vjs-default-skin .vjs-duration { float: left; }
|
||||
/* Remaining time is in the HTML, but not included in default design */
|
||||
.vjs-default-skin .vjs-remaining-time { display: none; float: left; }
|
||||
.vjs-time-divider { float: left; line-height: 3em; }
|
||||
|
||||
/* Fullscreen
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-default-skin .vjs-fullscreen-control {
|
||||
width: 3.8em;
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
}
|
||||
.vjs-default-skin .vjs-fullscreen-control:before {
|
||||
content: @fullscreen-enter-icon;
|
||||
}
|
||||
/* Switch to the exit icon when the player is in fullscreen */
|
||||
.vjs-default-skin.vjs-fullscreen .vjs-fullscreen-control:before {
|
||||
content: @fullscreen-exit-icon;
|
||||
}
|
||||
|
||||
/* Big Play Button (play button at start)
|
||||
--------------------------------------------------------------------------------
|
||||
Positioning of the play button in the center or other corners can be done more
|
||||
easily in the skin designer. http://designer.videojs.com/
|
||||
*/
|
||||
.vjs-default-skin .vjs-big-play-button {
|
||||
// Calculate total width/height so we're able to center the button
|
||||
@total-width: @big-play-width + (@big-play-border-width * 2);
|
||||
@total-height: @big-play-height + (@big-play-border-width * 2);
|
||||
// Position the button using the absolute-align mixin (bottom of page)
|
||||
.absolute-align(@big-play-align, @big-play-margin, @total-width);
|
||||
.absolute-align(@big-play-vertical-align, @big-play-margin, @total-height);
|
||||
|
||||
font-size: @big-play-font-size;
|
||||
display: block;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
width: @big-play-width;
|
||||
height: @big-play-height;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
|
||||
/* Need a slightly gray bg so it can be seen on black backgrounds *///
|
||||
.background-color-with-alpha(@big-play-bg-color, @big-play-bg-alpha);
|
||||
|
||||
border: @big-play-border-width solid @big-play-border-color;
|
||||
|
||||
.border-radius(@big-play-border-radius);
|
||||
.box-shadow(0px 0px 1em rgba(255, 255, 255, 0.25));
|
||||
.transition(all 0.4s);
|
||||
}
|
||||
|
||||
/* Optionally center */
|
||||
.vjs-default-skin.vjs-big-play-centered .vjs-big-play-button {
|
||||
@total-width: @big-play-width + (@big-play-border-width * 2);
|
||||
@total-height: @big-play-height + (@big-play-border-width * 2);
|
||||
|
||||
.absolute-align(center, @big-play-margin, @total-width);
|
||||
.absolute-align(middle, @big-play-margin, @total-height);
|
||||
}
|
||||
|
||||
/* Hide if controls are disabled */
|
||||
.vjs-default-skin.vjs-controls-disabled .vjs-big-play-button {
|
||||
display: none;
|
||||
}
|
||||
/* Hide when video starts playing */
|
||||
.vjs-default-skin.vjs-has-started .vjs-big-play-button {
|
||||
display: none;
|
||||
}
|
||||
/* Hide on mobile devices. Remove when we stop using native controls
|
||||
by default on mobile */
|
||||
.vjs-default-skin.vjs-using-native-controls .vjs-big-play-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vjs-default-skin:hover .vjs-big-play-button,
|
||||
.vjs-default-skin .vjs-big-play-button:focus {
|
||||
outline: 0;
|
||||
border-color: #fff;
|
||||
/* IE8 needs a non-glow hover state *///
|
||||
background-color: rgb(80, 80, 80);
|
||||
background-color: rgba(50, 50, 50, 0.75);
|
||||
|
||||
.box-shadow(0 0 3em #fff);
|
||||
.transition(all 0s);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-big-play-button:before {
|
||||
content: @play-icon;
|
||||
font-family: VideoJS;
|
||||
/* In order to center the play icon vertically we need to set the line height
|
||||
to the same as the button height */
|
||||
line-height: @big-play-height;
|
||||
text-shadow: 0.05em 0.05em 0.1em #000;
|
||||
text-align: center /* Needed for IE8 */;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Loading Spinner
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-loading-spinner {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
font-size: 4em;
|
||||
line-height: 1;
|
||||
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
|
||||
margin-left: -0.5em;
|
||||
margin-top: -0.5em;
|
||||
|
||||
opacity: 0.75;
|
||||
|
||||
.animation(spin 1.5s infinite linear);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-loading-spinner:before {
|
||||
content: @spinner3-icon;
|
||||
font-family: VideoJS;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
text-align: center;
|
||||
text-shadow: 0em 0em 0.1em #000;
|
||||
}
|
||||
|
||||
@-moz-keyframes spin {
|
||||
0% { -moz-transform: rotate(0deg); }
|
||||
100% { -moz-transform: rotate(359deg); }
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
0% { -webkit-transform: rotate(0deg); }
|
||||
100% { -webkit-transform: rotate(359deg); }
|
||||
}
|
||||
@-o-keyframes spin {
|
||||
0% { -o-transform: rotate(0deg); }
|
||||
100% { -o-transform: rotate(359deg); }
|
||||
}
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(359deg); }
|
||||
}
|
||||
|
||||
/* Menu Buttons (Captions/Subtitles/etc.)
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
.vjs-default-skin .vjs-menu-button {
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0em; /* (Width of vjs-menu - width of button) / 2 */
|
||||
width: 0em;
|
||||
height: 0em;
|
||||
margin-bottom: 3em;
|
||||
|
||||
border-left: 2em solid transparent;
|
||||
border-right: 2em solid transparent;
|
||||
|
||||
border-top: 1.55em solid rgb(0, 0, 0); /* Same width top as ul bottom */
|
||||
border-top-color: rgba(7, 40, 50, 0.5); /* Same as ul background */
|
||||
}
|
||||
|
||||
/* Button Pop-up Menu */
|
||||
.vjs-default-skin .vjs-menu-button .vjs-menu .vjs-menu-content {
|
||||
display: block;
|
||||
padding: 0; margin: 0;
|
||||
position: absolute;
|
||||
width: 10em;
|
||||
bottom: 1.5em; /* Same bottom as vjs-menu border-top */
|
||||
max-height: 15em;
|
||||
overflow: auto;
|
||||
|
||||
left: -5em; /* Width of menu - width of button / 2 */
|
||||
|
||||
.background-color-with-alpha(@control-bg-color, @control-bg-alpha);
|
||||
.box-shadow(-0.2em -0.2em 0.3em rgba(255, 255, 255, 0.2));
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-menu-button:hover .vjs-menu {
|
||||
display: block;
|
||||
}
|
||||
.vjs-default-skin .vjs-menu-button ul li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0.3em 0 0.3em 0;
|
||||
line-height: 1.4em;
|
||||
font-size: 1.2em;
|
||||
text-align: center;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
.vjs-default-skin .vjs-menu-button ul li.vjs-selected {
|
||||
background-color: #000;
|
||||
}
|
||||
.vjs-default-skin .vjs-menu-button ul li:focus,
|
||||
.vjs-default-skin .vjs-menu-button ul li:hover,
|
||||
.vjs-default-skin .vjs-menu-button ul li.vjs-selected:focus,
|
||||
.vjs-default-skin .vjs-menu-button ul li.vjs-selected:hover {
|
||||
outline: 0;
|
||||
color: #111;
|
||||
|
||||
.background-color-with-alpha(rgb(255, 255, 255), 0.75);
|
||||
.box-shadow(0 0 1em rgba(255, 255, 255, 1));
|
||||
}
|
||||
.vjs-default-skin .vjs-menu-button ul li.vjs-menu-title {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-size: 1em;
|
||||
line-height: 2em;
|
||||
padding: 0;
|
||||
margin: 0 0 0.3em 0;
|
||||
font-weight: bold;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Subtitles Button */
|
||||
.vjs-default-skin .vjs-subtitles-button:before { content: @subtitles-icon; }
|
||||
|
||||
/* Captions Button */
|
||||
.vjs-default-skin .vjs-captions-button:before {
|
||||
content: @captions-icon;
|
||||
}
|
||||
|
||||
/* Replacement for focus outline */
|
||||
.vjs-default-skin .vjs-captions-button:focus .vjs-control-content:before,
|
||||
.vjs-default-skin .vjs-captions-button:hover .vjs-control-content:before {
|
||||
.box-shadow(0 0 1em rgba(255, 255, 255, 1));
|
||||
}
|
||||
|
||||
/*
|
||||
REQUIRED STYLES (be careful overriding)
|
||||
================================================================================
|
||||
When loading the player, the video tag is replaced with a DIV,
|
||||
that will hold the video tag or object tag for other playback methods.
|
||||
The div contains the video playback element (Flash or HTML5) and controls,
|
||||
and sets the width and height of the video.
|
||||
|
||||
** If you want to add some kind of border/padding (e.g. a frame), or special
|
||||
positioning, use another containing element. Otherwise you risk messing up
|
||||
control positioning and full window mode. **
|
||||
*/
|
||||
.video-js {
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
/* Start with 10px for base font size so other dimensions can be em based and
|
||||
easily calculable. */
|
||||
font-size: @base-font-size;
|
||||
/* Allow poster to be vertially aligned. */
|
||||
vertical-align: middle;
|
||||
/* display: table-cell; */ /*This works in Safari but not Firefox.*/
|
||||
|
||||
/* Provide some basic defaults for fonts */
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
/* Avoiding helvetica: issue #376 */
|
||||
font-family: Arial, sans-serif;
|
||||
|
||||
/* Turn off user selection (text highlighting) by default.
|
||||
The majority of player components will not be text blocks.
|
||||
Text areas will need to turn user selection back on. */
|
||||
.user-select(none);
|
||||
}
|
||||
|
||||
/* Playback technology elements expand to the width/height of the containing div
|
||||
<video> or <object> */
|
||||
.video-js .vjs-tech {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
|
||||
checking fullScreenEnabled. */
|
||||
.video-js:-moz-full-screen { position: absolute; }
|
||||
|
||||
/* Fullscreen Styles */
|
||||
body.vjs-full-window {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
/* Fix for IE6 full-window. http://www.cssplay.co.uk/layouts/fixed.html *///
|
||||
overflow-y: auto;
|
||||
}
|
||||
.video-js.vjs-fullscreen {
|
||||
position: fixed;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
/* IE6 full-window (underscore hack) *///
|
||||
_position: absolute;
|
||||
}
|
||||
.video-js:-webkit-full-screen {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
.video-js.vjs-fullscreen.vjs-user-inactive {
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
/* Poster Styles */
|
||||
.vjs-poster {
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
background-size: contain;
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.vjs-poster img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-height: 100%;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Hide the poster when native controls are used otherwise it covers them */
|
||||
.video-js.vjs-using-native-controls .vjs-poster {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Text Track Styles */
|
||||
/* Overall track holder for both captions and subtitles */
|
||||
.video-js .vjs-text-track-display {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 4em;
|
||||
/* Leave padding on left and right *///
|
||||
left: 1em;
|
||||
right: 1em;
|
||||
}
|
||||
/* Individual tracks */
|
||||
.video-js .vjs-text-track {
|
||||
display: none;
|
||||
font-size: 1.4em;
|
||||
text-align: center;
|
||||
margin-bottom: 0.1em;
|
||||
/* Transparent black background, or fallback to all black (oldIE) *///
|
||||
.background-color-with-alpha(rgb(0, 0, 0), 0.5);
|
||||
}
|
||||
.video-js .vjs-subtitles { color: #fff /* Subtitles are white */; }
|
||||
.video-js .vjs-captions { color: #fc6 /* Captions are yellow */; }
|
||||
.vjs-tt-cue { display: block; }
|
||||
|
||||
/* Hide disabled or unsupported controls */
|
||||
.vjs-default-skin .vjs-hidden { display: none; }
|
||||
|
||||
.vjs-lock-showing {
|
||||
display: block !important;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
// MIXINS
|
||||
// =============================================================================
|
||||
// Mixins are a LESS feature and are used to add vendor prefixes to CSS rules
|
||||
// when needed.
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow
|
||||
.box-shadow (@string: 0 0 1em rgba(0, 0, 0, 0.25)) {
|
||||
/* box-shadow *///
|
||||
-webkit-box-shadow: @string;
|
||||
-moz-box-shadow: @string;
|
||||
box-shadow: @string;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius
|
||||
.border-radius (@string: 5px) {
|
||||
/* border-radius *///
|
||||
-webkit-border-radius: @string;
|
||||
-moz-border-radius: @string;
|
||||
border-radius: @string;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/transition
|
||||
.transition (@string: all 1s linear) {
|
||||
/* transition *///
|
||||
-webkit-transition: @string;
|
||||
-moz-transition: @string;
|
||||
-o-transition: @string;
|
||||
transition: @string;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/transition
|
||||
.transition-delay (@string: 1s) {
|
||||
/* transition-delay *///
|
||||
-webkit-transition-delay: @string;
|
||||
-moz-transition-delay: @string;
|
||||
-o-transition-delay: @string;
|
||||
transition-delay: @string;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/animation
|
||||
.animation (@string: spin 1s infinite linear) {
|
||||
/* animation *///
|
||||
-webkit-animation: @string;
|
||||
-moz-animation: @string;
|
||||
-o-animation: @string;
|
||||
animation: @string;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||
.transform (@string: rotate(-45deg)) {
|
||||
/* transform *///
|
||||
-webkit-transform: @string;
|
||||
-moz-transform: @string;
|
||||
-ms-transform: @string;
|
||||
-o-transform: @string;
|
||||
transform: @string;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/user-select
|
||||
.user-select (@string: none) {
|
||||
/* user-select *///
|
||||
-webkit-user-select: @string;
|
||||
-moz-user-select: @string;
|
||||
-ms-user-select: @string;
|
||||
user-select: @string;
|
||||
}
|
||||
|
||||
// Hide something visually but keep available for screen readers.
|
||||
// http://h5bp.com/v
|
||||
.hide-visually () {
|
||||
/* hide-visually *///
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position:
|
||||
absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
// Align an object with absolute positioning
|
||||
// Used to align the Big Play Button in the corners or center
|
||||
.absolute-align (@align, @margin, @length) when (@align = top) {
|
||||
top: @margin;
|
||||
}
|
||||
.absolute-align (@align, @margin, @length) when (@align = bottom) {
|
||||
bottom: @margin;
|
||||
}
|
||||
.absolute-align (@align, @margin, @length) when (@align = left) {
|
||||
left: @margin;
|
||||
}
|
||||
.absolute-align (@align, @margin, @length) when (@align = right) {
|
||||
right: @margin;
|
||||
}
|
||||
.absolute-align (@align, @margin, @length) when (@align = center) {
|
||||
/* Center it horizontally *///
|
||||
left: 50%;
|
||||
margin-left: -(@length / 2);
|
||||
}
|
||||
.absolute-align (@align, @margin, @length) when (@align = middle) {
|
||||
/* Center it vertically *///
|
||||
top: 50%;
|
||||
margin-top: -(@length / 2);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/637921/opacity-of-background-but-not-the-text
|
||||
.background-color-with-alpha (@color, @alpha) {
|
||||
@rgba: rgba(red(@color), green(@color), blue(@color), @alpha);
|
||||
/* background-color-with-alpha *///
|
||||
background-color: @color;
|
||||
background-color: @rgba;
|
||||
// No longer using MS filters because they break border radius in IE9
|
||||
// @argb: argb(@rgba);
|
||||
// filter: ~"progid:DXImageTransform.Microsoft.gradient(startColorstr=@{argb}, endColorstr=@{argb})";
|
||||
// -ms-filter: ~"progid:DXImageTransform.Microsoft.gradient(startColorstr=@{argb}, endColorstr=@{argb})";
|
||||
}
|
||||
|
||||
.border-color-with-alpha (@color, @alpha) {
|
||||
@rgba: rgba(red(@color), green(@color), blue(@color), @alpha);
|
||||
/* border-color-with-alpha *///
|
||||
border-color: @color;
|
||||
border-color: @rgba;
|
||||
}
|
||||
|
||||
// NOTES ON LESS (tracking learnings so we don't forget)
|
||||
// =============================================================================
|
||||
// * We want this file to continue to be accessible by people who don't know
|
||||
// LESS but know CSS. This means finding the balance between using the most
|
||||
// valuable LESS features (e.g. variables) and keeping it looking like CSS.
|
||||
// So it's best to avoid advanced LESS features like conditional statements.
|
||||
// (we're using one for the big play button position because that's a hot
|
||||
// topic)
|
||||
//
|
||||
// * We care about the readability of the CSS output of LESS, which means we
|
||||
// have to be careful about what features of LESS we use. (if you're building
|
||||
// your own skin this may not apply)
|
||||
// 1. Comments inside of rules (strangely) have an extra line added after
|
||||
// them in the CSS output. To avoid this we can add a LESS comment after
|
||||
// the CSS comment.
|
||||
// /* comment *///
|
||||
//
|
||||
// 2. In a rule with nested rules, any comments outside of a rule are moved
|
||||
// to the top of the parent rule. i.e. it might look like:
|
||||
// /* title of rule 1 */
|
||||
// /* title of rule 2 */
|
||||
// .rule1 {}
|
||||
// .rule2 {}
|
||||
// This is why we aren't using nested rules inside of the
|
||||
// vjs-default-skin class.
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
The original source of this file lives at
|
||||
https://github.com/videojs/video.js/blob/master/src/css/video-js.less */
|
||||
BIN
common/static/css/vendor/ova/video-js.png
vendored
|
Before Width: | Height: | Size: 4.0 KiB |
BIN
common/static/css/vendor/ova/videojs/skin/vjs.eot
vendored
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>
|
||||
This is a custom SVG font generated by IcoMoon.
|
||||
<iconset grid="16"></iconset>
|
||||
</metadata>
|
||||
<defs>
|
||||
<font id="VideoJS" horiz-adv-x="512" >
|
||||
<font-face units-per-em="512" ascent="480" descent="-32" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph class="hidden" unicode="" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
|
||||
<glyph unicode="" d="M 64,416L 224,416L 224,32L 64,32zM 288,416L 448,416L 448,32L 288,32z" />
|
||||
<glyph unicode="" d="M 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" />
|
||||
<glyph unicode="" d="M 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
|
||||
c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
|
||||
c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" />
|
||||
<glyph unicode="" d="M 359.765,64.235c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.372-9.372,24.568,0,33.941
|
||||
c 65.503,65.503, 65.503,172.085,0,237.588c-9.372,9.373-9.372,24.569,0,33.941c 9.372,9.371, 24.569,9.372, 33.941,0
|
||||
C 417.532,335.938, 440,281.696, 440,224c0-57.695-22.468-111.938-63.265-152.735C 372.049,66.578, 365.907,64.235, 359.765,64.235zM 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
|
||||
c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
|
||||
c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" />
|
||||
<glyph unicode="" d="M 445.020,18.98c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.373-9.372,24.568,0,33.941
|
||||
C 471.868,103.771, 496.001,162.030, 496.001,224c0,61.969-24.133,120.229-67.952,164.049c-9.372,9.373-9.372,24.569,0,33.941
|
||||
c 9.372,9.372, 24.569,9.372, 33.941,0c 52.885-52.886, 82.011-123.2, 82.011-197.99c0-74.791-29.126-145.104-82.011-197.99
|
||||
C 457.304,21.323, 451.162,18.98, 445.020,18.98zM 359.765,64.235c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.372-9.372,24.568,0,33.941
|
||||
c 65.503,65.503, 65.503,172.085,0,237.588c-9.372,9.373-9.372,24.569,0,33.941c 9.372,9.371, 24.569,9.372, 33.941,0
|
||||
C 417.532,335.938, 440,281.696, 440,224c0-57.695-22.468-111.938-63.265-152.735C 372.049,66.578, 365.907,64.235, 359.765,64.235zM 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
|
||||
c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
|
||||
c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" horiz-adv-x="544" />
|
||||
<glyph unicode="" d="M 256,480L 96,224L 256-32L 416,224 z" />
|
||||
<glyph unicode="" d="M 0,480 L 687.158,480 L 687.158-35.207 L 0-35.207 L 0,480 z M 622.731,224.638 C 621.878,314.664 618.46,353.922 597.131,381.656 C 593.291,387.629 586.038,391.042 580.065,395.304 C 559.158,410.669 460.593,416.211 346.247,416.211 C 231.896,416.211 128.642,410.669 108.162,395.304 C 101.762,391.042 94.504,387.629 90.242,381.656 C 69.331,353.922 66.349,314.664 65.069,224.638 C 66.349,134.607 69.331,95.353 90.242,67.62 C 94.504,61.22 101.762,58.233 108.162,53.967 C 128.642,38.18 231.896,33.060 346.247,32.207 C 460.593,33.060 559.158,38.18 580.065,53.967 C 586.038,58.233 593.291,61.22 597.131,67.62 C 618.46,95.353 621.878,134.607 622.731,224.638 z M 331.179,247.952 C 325.389,318.401 287.924,359.905 220.901,359.905 C 159.672,359.905 111.54,304.689 111.54,215.965 C 111.54,126.859 155.405,71.267 227.907,71.267 C 285.79,71.267 326.306,113.916 332.701,184.742 L 263.55,184.742 C 260.81,158.468 249.843,138.285 226.69,138.285 C 190.136,138.285 183.435,174.462 183.435,212.92 C 183.435,265.854 198.665,292.886 223.951,292.886 C 246.492,292.886 260.81,276.511 262.939,247.952 L 331.179,247.952 z M 570.013,247.952 C 564.228,318.401 526.758,359.905 459.74,359.905 C 398.507,359.905 350.379,304.689 350.379,215.965 C 350.379,126.859 394.244,71.267 466.746,71.267 C 524.625,71.267 565.14,113.916 571.536,184.742 L 502.384,184.742 C 499.649,158.468 488.682,138.285 465.529,138.285 C 428.971,138.285 422.27,174.462 422.27,212.92 C 422.27,265.854 437.504,292.886 462.785,292.886 C 485.327,292.886 499.649,276.511 501.778,247.952 L 570.013,247.952 z " horiz-adv-x="687.158" />
|
||||
<glyph unicode="" d="M 64,416L 448,416L 448,32L 64,32z" />
|
||||
<glyph unicode="" d="M 192,416A64,64 12780 1 1 320,416A64,64 12780 1 1 192,416zM 327.765,359.765A64,64 12780 1 1 455.765,359.765A64,64 12780 1 1 327.765,359.765zM 416,224A32,32 12780 1 1 480,224A32,32 12780 1 1 416,224zM 359.765,88.235A32,32 12780 1 1 423.765,88.23500000000001A32,32 12780 1 1 359.765,88.23500000000001zM 224.001,32A32,32 12780 1 1 288.001,32A32,32 12780 1 1 224.001,32zM 88.236,88.235A32,32 12780 1 1 152.236,88.23500000000001A32,32 12780 1 1 88.236,88.23500000000001zM 72.236,359.765A48,48 12780 1 1 168.236,359.765A48,48 12780 1 1 72.236,359.765zM 28,224A36,36 12780 1 1 100,224A36,36 12780 1 1 28,224z" />
|
||||
<glyph unicode="" d="M 224,192 L 224-16 L 144,64 L 48-32 L 0,16 L 96,112 L 16,192 ZM 512,432 L 416,336 L 496,256 L 288,256 L 288,464 L 368,384 L 464,480 Z" />
|
||||
<glyph unicode="" d="M 256,448 C 397.385,448 512,354.875 512,240 C 512,125.124 397.385,32 256,32 C 242.422,32 229.095,32.867 216.088,34.522 C 161.099-20.467 95.463-30.328 32-31.776 L 32-18.318 C 66.268-1.529 96,29.052 96,64 C 96,68.877 95.621,73.665 94.918,78.348 C 37.020,116.48 0,174.725 0,240 C 0,354.875 114.615,448 256,448 Z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 256,352
|
||||
c 70.692,0, 128-57.308, 128-128s-57.308-128-128-128s-128,57.308-128,128S 185.308,352, 256,352z M 408.735,71.265
|
||||
C 367.938,30.468, 313.695,8, 256,8c-57.696,0-111.938,22.468-152.735,63.265C 62.468,112.062, 40,166.304, 40,224
|
||||
c0,57.695, 22.468,111.938, 63.265,152.735l 33.941-33.941c0,0,0,0,0,0c-65.503-65.503-65.503-172.085,0-237.588
|
||||
C 168.937,73.475, 211.125,56, 256,56c 44.874,0, 87.062,17.475, 118.794,49.206c 65.503,65.503, 65.503,172.084,0,237.588l 33.941,33.941
|
||||
C 449.532,335.938, 472,281.695, 472,224C 472,166.304, 449.532,112.062, 408.735,71.265z" />
|
||||
<glyph unicode="" d="M 512,224c-0.639,33.431-7.892,66.758-21.288,97.231c-13.352,30.5-32.731,58.129-56.521,80.96
|
||||
c-23.776,22.848-51.972,40.91-82.492,52.826C 321.197,466.979, 288.401,472.693, 256,472c-32.405-0.641-64.666-7.687-94.167-20.678
|
||||
c-29.524-12.948-56.271-31.735-78.367-54.788c-22.112-23.041-39.58-50.354-51.093-79.899C 20.816,287.104, 15.309,255.375, 16,224
|
||||
c 0.643-31.38, 7.482-62.574, 20.067-91.103c 12.544-28.55, 30.738-54.414, 53.055-75.774c 22.305-21.377, 48.736-38.252, 77.307-49.36
|
||||
C 194.988-3.389, 225.652-8.688, 256-8c 30.354,0.645, 60.481,7.277, 88.038,19.457c 27.575,12.141, 52.558,29.74, 73.183,51.322
|
||||
c 20.641,21.57, 36.922,47.118, 47.627,74.715c 6.517,16.729, 10.94,34.2, 13.271,51.899c 0.623-0.036, 1.249-0.060, 1.881-0.060
|
||||
c 17.673,0, 32,14.326, 32,32c0,0.898-0.047,1.786-0.119,2.666L 512,223.999 z M 461.153,139.026c-11.736-26.601-28.742-50.7-49.589-70.59
|
||||
c-20.835-19.905-45.5-35.593-72.122-45.895C 312.828,12.202, 284.297,7.315, 256,8c-28.302,0.649-56.298,6.868-81.91,18.237
|
||||
c-25.625,11.333-48.842,27.745-67.997,47.856c-19.169,20.099-34.264,43.882-44.161,69.529C 51.997,169.264, 47.318,196.729, 48,224
|
||||
c 0.651,27.276, 6.664,54.206, 17.627,78.845c 10.929,24.65, 26.749,46.985, 46.123,65.405c 19.365,18.434, 42.265,32.935, 66.937,42.428
|
||||
C 203.356,420.208, 229.755,424.681, 256,424c 26.25-0.653, 52.114-6.459, 75.781-17.017c 23.676-10.525, 45.128-25.751, 62.812-44.391
|
||||
c 17.698-18.629, 31.605-40.647, 40.695-64.344C 444.412,274.552, 448.679,249.219, 448,224l 0.119,0 c-0.072-0.88-0.119-1.768-0.119-2.666
|
||||
c0-16.506, 12.496-30.087, 28.543-31.812C 473.431,172.111, 468.278,155.113, 461.153,139.026z" />
|
||||
<glyph unicode="" d="M 256,480 C 116.626,480 3.271,368.619 0.076,230.013 C 3.036,350.945 94.992,448 208,448 C 322.875,448 416,347.712 416,224 C 416,197.49 437.49,176 464,176 C 490.51,176 512,197.49 512,224 C 512,365.385 397.385,480 256,480 ZM 256-32 C 395.374-32 508.729,79.381 511.924,217.987 C 508.964,97.055 417.008,0 304,0 C 189.125,0 96,100.288 96,224 C 96,250.51 74.51,272 48,272 C 21.49,272 0,250.51 0,224 C 0,82.615 114.615-32 256-32 Z" />
|
||||
<glyph unicode="" d="M 432,128c-22.58,0-42.96-9.369-57.506-24.415L 158.992,211.336C 159.649,215.462, 160,219.689, 160,224
|
||||
s-0.351,8.538-1.008,12.663l 215.502,107.751C 389.040,329.369, 409.42,320, 432,320c 44.183,0, 80,35.817, 80,80S 476.183,480, 432,480
|
||||
s-80-35.817-80-80c0-4.311, 0.352-8.538, 1.008-12.663L 137.506,279.585C 122.96,294.63, 102.58,304, 80,304c-44.183,0-80-35.818-80-80
|
||||
c0-44.184, 35.817-80, 80-80c 22.58,0, 42.96,9.369, 57.506,24.414l 215.502-107.751C 352.352,56.538, 352,52.311, 352,48
|
||||
c0-44.184, 35.817-80, 80-80s 80,35.816, 80,80C 512,92.182, 476.183,128, 432,128z" />
|
||||
<glyph unicode="" d="M 96,416L 416,224L 96,32 z" />
|
||||
<glyph unicode="" d="M 512,480 L 512,272 L 432,352 L 336,256 L 288,304 L 384,400 L 304,480 ZM 224,144 L 128,48 L 208-32 L 0-32 L 0,176 L 80,96 L 176,192 Z" />
|
||||
<glyph unicode=" " horiz-adv-x="256" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 9.6 KiB |
BIN
common/static/css/vendor/ova/videojs/skin/vjs.ttf
vendored
BIN
common/static/css/vendor/ova/videojs/skin/vjs.woff
vendored
1075
common/static/js/vendor/ova/OpenSeaDragonAnnotation.js
vendored
@@ -1,1075 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
/**
|
||||
* Sets up a call so that every time the OpenSeaDragon instance is opened
|
||||
* it triggers the annotations to be redrawn.
|
||||
*/
|
||||
this.addHandler("open", function() {
|
||||
isOpenViewer = true;
|
||||
if (typeof self.annotationInstance!='undefined')
|
||||
self.annotationInstance.refreshDisplay();
|
||||
});
|
||||
annotator
|
||||
/**
|
||||
* This function is called once annotator has loaded the annotations.
|
||||
* It will then wait until the OSD instance has loaded to start drawing
|
||||
* the annotations.
|
||||
* @param Array annotations list of annotations from annotator instance
|
||||
*/
|
||||
.subscribe("annotationsLoaded", function (annotations){
|
||||
if (!self.annotationInstance) {
|
||||
|
||||
// annotation instance should include the OSD item and annotator
|
||||
self.annotationInstance = new $._annotation({
|
||||
viewer: self,
|
||||
annotator: annotator,
|
||||
});
|
||||
|
||||
// this collection of items is included as an item of annotator so
|
||||
// that there is a method to communicate back and forth.
|
||||
annotator.osda = self.annotationInstance;
|
||||
|
||||
// Because it takes a while for both OSD to open and for annotator
|
||||
// to get items from the backend, we wait until we get the "open" call
|
||||
function refreshDisplay(){
|
||||
if(!isOpenViewer){
|
||||
setTimeout(refreshDisplay,200);
|
||||
}else{
|
||||
self.annotationInstance.refreshDisplay();
|
||||
}
|
||||
}
|
||||
refreshDisplay();
|
||||
} else {
|
||||
self.annotationInstance.refreshDisplay();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Instance of the annotation package including OSD and Annotator
|
||||
* @constructor
|
||||
*/
|
||||
$._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 = {
|
||||
/**
|
||||
* This function makes sure that the OSD buttons are created, that the
|
||||
* panning and zooming functionality is created and the annotation events.
|
||||
*/
|
||||
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;
|
||||
},
|
||||
|
||||
/**
|
||||
* This function is called when the user changed from panning/zooming mode to
|
||||
* annotation creation mode. It allows the annotator to accept the creation of
|
||||
* a new annotation.
|
||||
*/
|
||||
newAnnotation:function(){
|
||||
var annotator = this.annotator;
|
||||
|
||||
// This variable tells editor that we want create an image annotation
|
||||
annotator.editor.OpenSeaDragon = this.viewer.id;
|
||||
|
||||
// allows the adder to actually show up
|
||||
annotator.adder.show();
|
||||
|
||||
// takes into account the various wrappers and instances to put the shape
|
||||
// over the correct place.
|
||||
this._setOverShape(annotator.adder);
|
||||
|
||||
// Open a new annotator dialog
|
||||
annotator.onAdderClick();
|
||||
},
|
||||
|
||||
/**
|
||||
* This function simply allows the editor to pop up with the given annotation.
|
||||
* @param {Object} annotation The annotation item from the backend server.
|
||||
* @param {TinyMCEEditor} editor The item that pops up when you edit an annotation.
|
||||
*/
|
||||
editAnnotation: function(annotation,editor){
|
||||
// Stupid check: is the annotation you're trying to edit an image?
|
||||
if (this._isOpenSeaDragon(annotation)){
|
||||
|
||||
var editor = editor || this.annotator.editor;
|
||||
|
||||
// set the editor over the highlighted element
|
||||
this._setOverShape(editor.element);
|
||||
editor.checkOrientation();
|
||||
|
||||
// makes sure that we are making an image annotation
|
||||
editor.OpenSeaDragon = this.viewer.id;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function gets the annotations from the last annotator query and sorts
|
||||
* them and draws them onto the OpenSeaDragon instance. It also publishes
|
||||
* a notification in case the colorize the annotations.
|
||||
*/
|
||||
refreshDisplay: function(){
|
||||
var allannotations = this.annotator.plugins['Store'].annotations;
|
||||
var annotator = this.annotator;
|
||||
|
||||
// Sort the annotations by date
|
||||
this._sortByDate(allannotations);
|
||||
|
||||
// remove all of 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);
|
||||
}
|
||||
}
|
||||
|
||||
// if the colored highlights by tags plugin it is notified to colorize
|
||||
annotator.publish('externalCallToHighlightTags', [an]);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function get notified every time we switch from panning/zooming mode onto
|
||||
* annotation creation mode.
|
||||
* @param {Event} e This is the event passed in from the OSD buttons.
|
||||
*/
|
||||
modeAnnotation:function(e){
|
||||
this._reset();
|
||||
var viewer = this.viewer;
|
||||
if (!this.isAnnotating){
|
||||
// When annotating, the cursor turns into a crosshair and there is a
|
||||
// green border around the OSD instance.
|
||||
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{
|
||||
// Otherwise, the cursor is a cross with four arrows to indicate movement
|
||||
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");
|
||||
}
|
||||
|
||||
// toggles the annotating flag
|
||||
this.isAnnotating = !this.isAnnotating?true:false;
|
||||
},
|
||||
|
||||
/**
|
||||
* This function takes in an annotation and draws the box indicating the area
|
||||
* that has been annotated.
|
||||
* @param {Object} an Annotation item from the list in the Annotator instance.
|
||||
*/
|
||||
drawRect:function(an){
|
||||
// Stupid check: Does this annotation actually have an area of annotation
|
||||
if (typeof an.rangePosition!='undefined'){
|
||||
// Sets up the visual aspects of the area for the user
|
||||
var span = document.createElement('span');
|
||||
var rectPosition = an.rangePosition;
|
||||
span.className = "annotator-hl";
|
||||
|
||||
// outline and border below create a double line one black and one white
|
||||
// so to be able to differentiate when selecting dark or light images
|
||||
span.style.border = '2px solid rgb(255, 255, 255)';
|
||||
span.style.outline = '2px solid rgb(0, 0, 0)';
|
||||
span.style.background = 'rgba(0,0,0,0)';
|
||||
|
||||
// Adds listening items for the viewer and editor
|
||||
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);
|
||||
|
||||
// Sends the element created to the proper location within the OSD instance
|
||||
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;
|
||||
},
|
||||
|
||||
/**
|
||||
* This changes the variable rectPosition to the proper location based on
|
||||
* screen coordinates and OSD image coordinates.
|
||||
*/
|
||||
setRectPosition:function(){
|
||||
// Get the actual locations of the rectangle
|
||||
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);
|
||||
|
||||
// return the proper value of the rectangle
|
||||
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 */
|
||||
|
||||
/**
|
||||
* When the user starts clicking this will create a rectangle that will be a
|
||||
* temporary position that is to be later scaled via dragging
|
||||
* @param {Event} event The actual action of clicking down.
|
||||
*/
|
||||
_onCanvasMouseDown: function(event) {
|
||||
|
||||
// action is ONLY performed if we are in annotation creation mode
|
||||
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)';
|
||||
|
||||
// outline and border below create a double line one black and one white
|
||||
// so to be able to differentiate when selecting dark or light images
|
||||
this.rect.style.border = '2px solid rgb(255, 255, 255)';
|
||||
this.rect.style.outline = '2px solid rgb(0, 0, 0)';
|
||||
|
||||
this.rect.style.position = 'absolute';
|
||||
this.rect.className = 'DrawingRect';
|
||||
// set the initial position
|
||||
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);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* When the user has clicked and is now dragging to create an annotation area,
|
||||
* the following function resizes the area selected.
|
||||
* @param {Event} event The actual action of dragging every time it is dragged.
|
||||
*/
|
||||
_onCanvasMouseMove: function(event) {
|
||||
|
||||
// of course, this only runs when we are in annotation creation mode and
|
||||
// when the user has clicked down (and is therefore drawing the rectangle)
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will finish drawing the rectangle, get its current position
|
||||
* and then open up the editor to make the annotation.
|
||||
*/
|
||||
_onDocumentMouseUp: function() {
|
||||
|
||||
// Stupid check: only do it when in annotation creation mode and
|
||||
// when the user has begun making a rectangle over the annotation area
|
||||
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();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will trigger the viewer to show up whenever an item is hovered
|
||||
* over and will cause the background color of the area to change a bit.
|
||||
* @param {Event} event The actual action of moving the mouse over an element.
|
||||
*/
|
||||
_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;
|
||||
|
||||
// if the current position of the mouse is within the bounds of an area
|
||||
// change the background of that area to a light yellow to simulate
|
||||
// a hover. Otherwise, keep it translucent.
|
||||
this.style.background = (y <= maxy && y >= t) && (x <= maxx && x >= l)?
|
||||
'rgba(255, 255, 10, 0.05)':'rgba(0, 0, 0, 0)';
|
||||
|
||||
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 the user is hovering over multiple annotation areas,
|
||||
// they will be stacked as usual
|
||||
if (annotations.length>0) annotator.showViewer(jQuery.makeArray(annotations), mousePosition);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will zoom/pan the user into the bounding area of the annotation.
|
||||
* @param {Event} event The actual action of clicking down within an annotation area.
|
||||
*/
|
||||
_onAnnotationClick: function(event){
|
||||
// gets the annotation from the data stored in the element
|
||||
var an = jQuery.data(event.target, 'annotation');
|
||||
// gets the bound within the annotation data
|
||||
var bounds = typeof an.bounds!='undefined'?an.bounds:{};
|
||||
var currentBounds = this.viewer.drawer.viewport.getBounds();
|
||||
// if the area is not already panned and zoomed in to the correct area
|
||||
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 parameter
|
||||
this.viewer.drawer.viewport.fitBounds(currentBounds);
|
||||
},
|
||||
|
||||
/* Utilities */
|
||||
/**
|
||||
* This function will return an array of sorted items
|
||||
* @param {Array} annotations List of annotations from annotator instance.
|
||||
* @param {String} type Either 'asc' for ascending or 'desc' for descending
|
||||
*/
|
||||
_sortByDate: function (annotations,type){
|
||||
var type = type || 'asc'; // asc => The value [0] will be the most recent date
|
||||
annotations.sort(function(a,b){
|
||||
// gets the date from when they were last updated
|
||||
a = new Date(typeof a.updated!='undefined'?createDateFromISO8601(a.updated):'');
|
||||
b = new Date(typeof b.updated!='undefined'?createDateFromISO8601(b.updated):'');
|
||||
|
||||
// orders them based on type passed in
|
||||
if (type == 'asc')
|
||||
return b<a?-1:b>a?1:0;
|
||||
else
|
||||
return a<b?-1:a>b?1:0;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* This function creates the button that will switch back and forth between
|
||||
* annotation creation mode and panning/zooming mode.
|
||||
*/
|
||||
_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
|
||||
});
|
||||
|
||||
// area makes sure that the annotation button only appears when everyone is
|
||||
// allowed to annotate or if you are an instructor
|
||||
if(this.options.viewer.annotation_mode == "everyone" || this.options.viewer.flags){
|
||||
/* 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}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This function makes sure that if you're switching to panning/zooming mode,
|
||||
* the last rectangle you drew (but didn't save) gets destroyed.
|
||||
*/
|
||||
_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';
|
||||
},
|
||||
|
||||
/**
|
||||
* This function binds the function to the object it was created from
|
||||
* @param {function} fn This is the function you want to apply
|
||||
* @param {Object} me This is the object you should pass it to (usually itself)
|
||||
*/
|
||||
__bind: function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
|
||||
/**
|
||||
* Remove all the elements with a given name inside "inElement" to maintain
|
||||
* a limited scope.
|
||||
* @param {String} className Class that should be removed
|
||||
* @param {HTMLElement} inElement Element in which classes should be removed
|
||||
*/
|
||||
_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 and there's a target, open
|
||||
* OSD instance.
|
||||
* @param {Object} an Annotation from the Annotator instance
|
||||
*/
|
||||
_isOpenSeaDragon: function (an){
|
||||
var annotator = this.annotator;
|
||||
var rp = an.rangePosition;
|
||||
|
||||
// Makes sure OSD exists and that annotation is an image annotation
|
||||
// with a position in the OSD instance
|
||||
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;
|
||||
|
||||
// Though it would be better to store server ids of images in the annotation that
|
||||
// would require changing annotations that were already made, instead we check if
|
||||
// the id is a substring of the thumbnail, which according to OpenSeaDragon API should be the case.
|
||||
var sourceId = this.viewer.source['@id'];
|
||||
|
||||
// code runs on annotation creation before thumbnail is created
|
||||
var targetThumb = an.target ? an.target.thumb : false;
|
||||
if (isContainer) {
|
||||
// reason why this is okay is that we are trying to ascertain that the annotation
|
||||
// is related to the image drawn. If thumbnail attribute is empty it means the annotation
|
||||
// was just created and should still be considered an annotation of this image.
|
||||
isSource = targetThumb ? (targetThumb.indexOf(sourceId) !== -1) : true;
|
||||
}
|
||||
return (isOpenSeaDragon && isContainer && isImage && isRP && isSource);
|
||||
},
|
||||
|
||||
/* Annotator Utilities */
|
||||
/**
|
||||
* Makes sure that absolute x and y values for overlayed section are
|
||||
* calculated to match area within OSD instance
|
||||
* @param {HTMLElement} elem Element where shape is overlayed
|
||||
*/
|
||||
_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 based on annotator wrapper and OSD area
|
||||
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 */
|
||||
/**
|
||||
* Given a point of x and y values in pixels it will return a point with
|
||||
* percentages in relation to the Image object
|
||||
* @param {$.Point} point Canvas relative coordinates in pixels
|
||||
* @return {$.Point} Returns Image relative percentages
|
||||
*/
|
||||
_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);
|
||||
},
|
||||
|
||||
/**
|
||||
* Given values in percentage relatives to the image it will return a point in
|
||||
* pixels related to the canvas element.
|
||||
* @param {$.Point} point Image relative percentages
|
||||
* @return {$.Point} Returns canvas relative coordinates in pixels
|
||||
*/
|
||||
_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);
|
||||
|
||||
/**
|
||||
* Creates an instance of the plugin that interacts with OpenSeaDragon.
|
||||
* @constructor
|
||||
*/
|
||||
function OpenSeaDragon() {
|
||||
this.pluginSubmit = __bind(this.pluginSubmit, this);
|
||||
_ref = OpenSeaDragon.__super__.constructor.apply(this, arguments);
|
||||
|
||||
// To facilitate calling items, we want to be able to get the index of a value
|
||||
this.__indexOf = [].indexOf;
|
||||
if(!this.__indexOf){
|
||||
|
||||
// Basically you iterate through every item on the list, if it matches
|
||||
// the item you are looking for return the current index, otherwise return -1
|
||||
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;
|
||||
|
||||
/**
|
||||
* This function initiates the editor that will apear when you edit/create an
|
||||
* annotation and the viewer that appears when you hover over an item.
|
||||
*/
|
||||
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');
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called by annotator whenever user hits the "Save" Button. It will
|
||||
* first check to see if the user is editing or creating and then save the
|
||||
* metadata for the image in an object that will be passed to the backend.
|
||||
*/
|
||||
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(isNew){
|
||||
// if it's undefined, we know it's an image because the editor within
|
||||
// the OSD instance was open
|
||||
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)
|
||||
|
||||
// Gets the bounds in order to save them for zooming in and highlight properties
|
||||
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"]);
|
||||
|
||||
// creates a link to the OSD server that contains the image to get
|
||||
// the thumbnail of the selected portion of the image
|
||||
annotation.target.thumb = finalimagelink + "/" + highlightX + "," + highlightY + "," + highlightWidth + "," + highlightHeight + "/full/0/native." + source["formats"][0];
|
||||
if(isNew) annotation.rangePosition = position || {}; // - rangePosition
|
||||
|
||||
// updates the dates associated with creation and update
|
||||
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 image annotation and there's a target, open
|
||||
* OSD instance.
|
||||
* @param {Object} an Annotation from the Annotator instance
|
||||
*/
|
||||
OpenSeaDragon.prototype.isOpenSeaDragon = function (an){
|
||||
var annotator = this.annotator;
|
||||
var rp = an.rangePosition;
|
||||
|
||||
// Makes sure OSD exists and that annotation is an image annotation
|
||||
// with a position in the OSD instance
|
||||
var isOpenSeaDragon = (typeof annotator.osda != 'undefined');
|
||||
var isContainer = (typeof an.target!='undefined' && an.target.container==osda.viewer.id );
|
||||
var isImage = (typeof an.media!='undefined' && an.media=='image');
|
||||
var isRP = (typeof rp!='undefined');
|
||||
var isSource = false;
|
||||
|
||||
// Double checks that the image being displayed matches the annotations
|
||||
var source = 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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes the OSD annotation from Annotator and refreshes display to remove element
|
||||
* @param {Object} an Annotation object from the Annotator instance
|
||||
*/
|
||||
OpenSeaDragon.prototype._deleteAnnotation = function(an){
|
||||
// Remove the annotation of the plugin Store
|
||||
var annotations = this.annotator.plugins['Store'].annotations;
|
||||
|
||||
// Failsafe in case annotation is not immediately removed from annotations list
|
||||
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(0, 0, 0, 0)';
|
||||
});
|
||||
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;
|
||||
|
||||
// We need to make sure that osda is accessible via annotator
|
||||
this.annotator.osda = this;
|
||||
|
||||
function reloadEditor(){
|
||||
tinymce.EditorManager.execCommand('mceRemoveEditor',true, "annotator-field-0");
|
||||
tinymce.EditorManager.execCommand('mceAddEditor',true, "annotator-field-0");
|
||||
|
||||
// if person hits into/out of fullscreen before closing the editor should close itself
|
||||
// ideally we would want to keep it open and reposition, this would make a great TODO in the future
|
||||
annotator.editor.hide();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
document.addEventListener("fullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
document.addEventListener("mozfullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
document.addEventListener("webkitfullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
document.addEventListener("msfullscreenchange", function () {
|
||||
reloadEditor();
|
||||
}, false);
|
||||
|
||||
// for some reason the above doesn't work when person hits ESC to exit full screen...
|
||||
$(document).keyup(function(e) {
|
||||
// esc key reloads editor as well
|
||||
if (e.keyCode == 27) {
|
||||
reloadEditor();
|
||||
}
|
||||
});
|
||||
|
||||
this.options = options;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
Annotator.Plugin.Auth.prototype.haveValidToken = function() {
|
||||
return (
|
||||
this._unsafeToken &&
|
||||
this._unsafeToken.d.issuedAt &&
|
||||
this._unsafeToken.d.ttl &&
|
||||
this._unsafeToken.d.consumerKey &&
|
||||
this.timeToExpiry() > 0
|
||||
);
|
||||
};
|
||||
|
||||
Annotator.Plugin.Auth.prototype.timeToExpiry = function() {
|
||||
var expiry, issue, now, timeToExpiry;
|
||||
now = new Date().getTime() / 1000;
|
||||
issue = createDateFromISO8601(this._unsafeToken.d.issuedAt).getTime() / 1000;
|
||||
expiry = issue + this._unsafeToken.d.ttl;
|
||||
timeToExpiry = expiry - now;
|
||||
if (timeToExpiry > 0) {
|
||||
return timeToExpiry;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
3373
common/static/js/vendor/ova/annotator-full.js
vendored
@@ -1,3373 +0,0 @@
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
** Annotator v1.2.8-dev-0acc077
|
||||
** https://github.com/okfn/annotator/
|
||||
**
|
||||
** Copyright 2012 Aron Carroll, Rufus Pollock, and Nick Stenning.
|
||||
** Dual licensed under the MIT and GPLv3 licenses.
|
||||
** https://github.com/okfn/annotator/blob/master/LICENSE
|
||||
**
|
||||
** Built at: 2013-11-25 17:25:07Z
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var findChild, getNodeName, getNodePosition, simpleXPathJQuery, simpleXPathPure;
|
||||
|
||||
simpleXPathJQuery = function(relativeRoot) {
|
||||
var jq;
|
||||
jq = this.map(function() {
|
||||
var elem, idx, path, tagName;
|
||||
path = '';
|
||||
elem = this;
|
||||
while ((elem != null ? elem.nodeType : void 0) === Node.ELEMENT_NODE && elem !== relativeRoot) {
|
||||
tagName = elem.tagName.replace(":", "\\:");
|
||||
idx = $(elem.parentNode).children(tagName).index(elem) + 1;
|
||||
idx = "[" + idx + "]";
|
||||
path = "/" + elem.tagName.toLowerCase() + idx + path;
|
||||
elem = elem.parentNode;
|
||||
}
|
||||
return path;
|
||||
});
|
||||
return jq.get();
|
||||
};
|
||||
|
||||
simpleXPathPure = function(relativeRoot) {
|
||||
var getPathSegment, getPathTo, jq, rootNode;
|
||||
getPathSegment = function(node) {
|
||||
var name, pos;
|
||||
name = getNodeName(node);
|
||||
pos = getNodePosition(node);
|
||||
return "" + name + "[" + pos + "]";
|
||||
};
|
||||
rootNode = relativeRoot;
|
||||
getPathTo = function(node) {
|
||||
var xpath;
|
||||
xpath = '';
|
||||
while (node !== rootNode) {
|
||||
if (node == null) {
|
||||
throw new Error("Called getPathTo on a node which was not a descendant of @rootNode. " + rootNode);
|
||||
}
|
||||
xpath = (getPathSegment(node)) + '/' + xpath;
|
||||
node = node.parentNode;
|
||||
}
|
||||
xpath = '/' + xpath;
|
||||
xpath = xpath.replace(/\/$/, '');
|
||||
return xpath;
|
||||
};
|
||||
jq = this.map(function() {
|
||||
var path;
|
||||
path = getPathTo(this);
|
||||
return path;
|
||||
});
|
||||
return jq.get();
|
||||
};
|
||||
|
||||
findChild = function(node, type, index) {
|
||||
var child, children, found, name, _i, _len;
|
||||
if (!node.hasChildNodes()) {
|
||||
throw new Error("XPath error: node has no children!");
|
||||
}
|
||||
children = node.childNodes;
|
||||
found = 0;
|
||||
for (_i = 0, _len = children.length; _i < _len; _i++) {
|
||||
child = children[_i];
|
||||
name = getNodeName(child);
|
||||
if (name === type) {
|
||||
found += 1;
|
||||
if (found === index) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Error("XPath error: wanted child not found.");
|
||||
};
|
||||
|
||||
getNodeName = function(node) {
|
||||
var nodeName;
|
||||
nodeName = node.nodeName.toLowerCase();
|
||||
switch (nodeName) {
|
||||
case "#text":
|
||||
return "text()";
|
||||
case "#comment":
|
||||
return "comment()";
|
||||
case "#cdata-section":
|
||||
return "cdata-section()";
|
||||
default:
|
||||
return nodeName;
|
||||
}
|
||||
};
|
||||
|
||||
getNodePosition = function(node) {
|
||||
var pos, tmp;
|
||||
pos = 0;
|
||||
tmp = node;
|
||||
while (tmp) {
|
||||
if (tmp.nodeName === node.nodeName) {
|
||||
pos++;
|
||||
}
|
||||
tmp = tmp.previousSibling;
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var $, Util, gettext_annotator, _ref, _t;
|
||||
|
||||
gettext_annotator = function(msgid) {
|
||||
return msgid;
|
||||
};
|
||||
|
||||
_t = function(msgid) {
|
||||
return gettext_annotator(msgid);
|
||||
};
|
||||
|
||||
if (!(typeof jQuery !== "undefined" && jQuery !== null ? (_ref = jQuery.fn) != null ? _ref.jquery : void 0 : void 0)) {
|
||||
console.error(_t("Annotator requires jQuery: have you included lib/vendor/jquery.js?"));
|
||||
}
|
||||
|
||||
if (!(JSON && JSON.parse && JSON.stringify)) {
|
||||
console.error(_t("Annotator requires a JSON implementation: have you included lib/vendor/json2.js?"));
|
||||
}
|
||||
|
||||
$ = jQuery;
|
||||
|
||||
Util = {};
|
||||
|
||||
Util.flatten = function(array) {
|
||||
var flatten;
|
||||
flatten = function(ary) {
|
||||
var el, flat, _i, _len;
|
||||
flat = [];
|
||||
for (_i = 0, _len = ary.length; _i < _len; _i++) {
|
||||
el = ary[_i];
|
||||
flat = flat.concat(el && $.isArray(el) ? flatten(el) : el);
|
||||
}
|
||||
return flat;
|
||||
};
|
||||
return flatten(array);
|
||||
};
|
||||
|
||||
Util.contains = function(parent, child) {
|
||||
var node;
|
||||
node = child;
|
||||
while (node != null) {
|
||||
if (node === parent) {
|
||||
return true;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Util.getTextNodes = function(jq) {
|
||||
var getTextNodes;
|
||||
getTextNodes = function(node) {
|
||||
var nodes;
|
||||
if (node && node.nodeType !== Node.TEXT_NODE) {
|
||||
nodes = [];
|
||||
if (node.nodeType !== Node.COMMENT_NODE) {
|
||||
node = node.lastChild;
|
||||
while (node) {
|
||||
nodes.push(getTextNodes(node));
|
||||
node = node.previousSibling;
|
||||
}
|
||||
}
|
||||
return nodes.reverse();
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
};
|
||||
return jq.map(function() {
|
||||
return Util.flatten(getTextNodes(this));
|
||||
});
|
||||
};
|
||||
|
||||
Util.getLastTextNodeUpTo = function(n) {
|
||||
var result;
|
||||
switch (n.nodeType) {
|
||||
case Node.TEXT_NODE:
|
||||
return n;
|
||||
case Node.ELEMENT_NODE:
|
||||
if (n.lastChild != null) {
|
||||
result = Util.getLastTextNodeUpTo(n.lastChild);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
n = n.previousSibling;
|
||||
if (n != null) {
|
||||
return Util.getLastTextNodeUpTo(n);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Util.getFirstTextNodeNotBefore = function(n) {
|
||||
var result;
|
||||
switch (n.nodeType) {
|
||||
case Node.TEXT_NODE:
|
||||
return n;
|
||||
case Node.ELEMENT_NODE:
|
||||
if (n.firstChild != null) {
|
||||
result = Util.getFirstTextNodeNotBefore(n.firstChild);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
n = n.nextSibling;
|
||||
if (n != null) {
|
||||
return Util.getFirstTextNodeNotBefore(n);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Util.readRangeViaSelection = function(range) {
|
||||
var sel;
|
||||
sel = Util.getGlobal().getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range.toRange());
|
||||
return sel.toString();
|
||||
};
|
||||
|
||||
Util.xpathFromNode = function(el, relativeRoot) {
|
||||
var exception, result;
|
||||
try {
|
||||
result = simpleXPathJQuery.call(el, relativeRoot);
|
||||
} catch (_error) {
|
||||
exception = _error;
|
||||
console.log("jQuery-based XPath construction failed! Falling back to manual.");
|
||||
result = simpleXPathPure.call(el, relativeRoot);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Util.nodeFromXPath = function(xp, root) {
|
||||
var idx, name, node, step, steps, _i, _len, _ref1;
|
||||
steps = xp.substring(1).split("/");
|
||||
node = root;
|
||||
for (_i = 0, _len = steps.length; _i < _len; _i++) {
|
||||
step = steps[_i];
|
||||
_ref1 = step.split("["), name = _ref1[0], idx = _ref1[1];
|
||||
idx = idx != null ? parseInt((idx != null ? idx.split("]") : void 0)[0]) : 1;
|
||||
node = findChild(node, name.toLowerCase(), idx);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
Util.escape = function(html) {
|
||||
return html.replace(/&(?!\w+;)/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
};
|
||||
|
||||
Util.uuid = (function() {
|
||||
var counter;
|
||||
counter = 0;
|
||||
return function() {
|
||||
return counter++;
|
||||
};
|
||||
})();
|
||||
|
||||
Util.getGlobal = function() {
|
||||
return (function() {
|
||||
return this;
|
||||
})();
|
||||
};
|
||||
|
||||
Util.maxZIndex = function($elements) {
|
||||
var all, el;
|
||||
all = (function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = $elements.length; _i < _len; _i++) {
|
||||
el = $elements[_i];
|
||||
if ($(el).css('position') === 'static') {
|
||||
_results.push(-1);
|
||||
} else {
|
||||
_results.push(parseInt($(el).css('z-index'), 10) || -1);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
return Math.max.apply(Math, all);
|
||||
};
|
||||
|
||||
Util.mousePosition = function(e, offsetEl) {
|
||||
var offset, _ref1;
|
||||
if ((_ref1 = $(offsetEl).css('position')) !== 'absolute' && _ref1 !== 'fixed' && _ref1 !== 'relative') {
|
||||
offsetEl = $(offsetEl).offsetParent()[0];
|
||||
}
|
||||
offset = $(offsetEl).offset();
|
||||
return {
|
||||
top: e.pageY - offset.top,
|
||||
left: e.pageX - offset.left
|
||||
};
|
||||
};
|
||||
|
||||
Util.preventEventDefault = function(event) {
|
||||
return event != null ? typeof event.preventDefault === "function" ? event.preventDefault() : void 0 : void 0;
|
||||
};
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var fn, functions, _i, _j, _len, _len1,
|
||||
__slice = [].slice;
|
||||
|
||||
functions = ["log", "debug", "info", "warn", "exception", "assert", "dir", "dirxml", "trace", "group", "groupEnd", "groupCollapsed", "time", "timeEnd", "profile", "profileEnd", "count", "clear", "table", "error", "notifyFirebug", "firebug", "userObjects"];
|
||||
|
||||
if (typeof console !== "undefined" && console !== null) {
|
||||
if (console.group == null) {
|
||||
console.group = function(name) {
|
||||
return console.log("GROUP: ", name);
|
||||
};
|
||||
}
|
||||
if (console.groupCollapsed == null) {
|
||||
console.groupCollapsed = console.group;
|
||||
}
|
||||
for (_i = 0, _len = functions.length; _i < _len; _i++) {
|
||||
fn = functions[_i];
|
||||
if (console[fn] == null) {
|
||||
console[fn] = function() {
|
||||
return console.log(_t("Not implemented:") + (" console." + name));
|
||||
};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.console = {};
|
||||
for (_j = 0, _len1 = functions.length; _j < _len1; _j++) {
|
||||
fn = functions[_j];
|
||||
this.console[fn] = function() {};
|
||||
}
|
||||
this.console['error'] = function() {
|
||||
var args;
|
||||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
||||
return alert("ERROR: " + (args.join(', ')));
|
||||
};
|
||||
this.console['warn'] = function() {
|
||||
var args;
|
||||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
||||
return alert("WARNING: " + (args.join(', ')));
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var Delegator,
|
||||
__slice = [].slice,
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
Delegator = (function() {
|
||||
Delegator.prototype.events = {};
|
||||
|
||||
Delegator.prototype.options = {};
|
||||
|
||||
Delegator.prototype.element = null;
|
||||
|
||||
function Delegator(element, options) {
|
||||
this.options = $.extend(true, {}, this.options, options);
|
||||
this.element = $(element);
|
||||
this._closures = {};
|
||||
this.on = this.subscribe;
|
||||
this.addEvents();
|
||||
}
|
||||
|
||||
Delegator.prototype.addEvents = function() {
|
||||
var event, _i, _len, _ref, _results;
|
||||
_ref = Delegator._parseEvents(this.events);
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
event = _ref[_i];
|
||||
_results.push(this._addEvent(event.selector, event.event, event.functionName));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Delegator.prototype.removeEvents = function() {
|
||||
var event, _i, _len, _ref, _results;
|
||||
_ref = Delegator._parseEvents(this.events);
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
event = _ref[_i];
|
||||
_results.push(this._removeEvent(event.selector, event.event, event.functionName));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Delegator.prototype._addEvent = function(selector, event, functionName) {
|
||||
var closure,
|
||||
_this = this;
|
||||
closure = function() {
|
||||
return _this[functionName].apply(_this, arguments);
|
||||
};
|
||||
if (selector === '' && Delegator._isCustomEvent(event)) {
|
||||
this.subscribe(event, closure);
|
||||
} else {
|
||||
this.element.delegate(selector, event, closure);
|
||||
}
|
||||
this._closures["" + selector + "/" + event + "/" + functionName] = closure;
|
||||
return this;
|
||||
};
|
||||
|
||||
Delegator.prototype._removeEvent = function(selector, event, functionName) {
|
||||
var closure;
|
||||
closure = this._closures["" + selector + "/" + event + "/" + functionName];
|
||||
if (selector === '' && Delegator._isCustomEvent(event)) {
|
||||
this.unsubscribe(event, closure);
|
||||
} else {
|
||||
this.element.undelegate(selector, event, closure);
|
||||
}
|
||||
delete this._closures["" + selector + "/" + event + "/" + functionName];
|
||||
return this;
|
||||
};
|
||||
|
||||
Delegator.prototype.publish = function() {
|
||||
this.element.triggerHandler.apply(this.element, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
Delegator.prototype.subscribe = function(event, callback) {
|
||||
var closure;
|
||||
closure = function() {
|
||||
return callback.apply(this, [].slice.call(arguments, 1));
|
||||
};
|
||||
closure.guid = callback.guid = ($.guid += 1);
|
||||
this.element.bind(event, closure);
|
||||
return this;
|
||||
};
|
||||
|
||||
Delegator.prototype.unsubscribe = function() {
|
||||
this.element.unbind.apply(this.element, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
return Delegator;
|
||||
|
||||
})();
|
||||
|
||||
Delegator._parseEvents = function(eventsObj) {
|
||||
var event, events, functionName, sel, selector, _i, _ref;
|
||||
events = [];
|
||||
for (sel in eventsObj) {
|
||||
functionName = eventsObj[sel];
|
||||
_ref = sel.split(' '), selector = 2 <= _ref.length ? __slice.call(_ref, 0, _i = _ref.length - 1) : (_i = 0, []), event = _ref[_i++];
|
||||
events.push({
|
||||
selector: selector.join(' '),
|
||||
event: event,
|
||||
functionName: functionName
|
||||
});
|
||||
}
|
||||
return events;
|
||||
};
|
||||
|
||||
Delegator.natives = (function() {
|
||||
var key, specials, val;
|
||||
specials = (function() {
|
||||
var _ref, _results;
|
||||
_ref = jQuery.event.special;
|
||||
_results = [];
|
||||
for (key in _ref) {
|
||||
if (!__hasProp.call(_ref, key)) continue;
|
||||
val = _ref[key];
|
||||
_results.push(key);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
return "blur focus focusin focusout load resize scroll unload click dblclick\nmousedown mouseup mousemove mouseover mouseout mouseenter mouseleave\nchange select submit keydown keypress keyup error".split(/[^a-z]+/).concat(specials);
|
||||
})();
|
||||
|
||||
Delegator._isCustomEvent = function(event) {
|
||||
event = event.split('.')[0];
|
||||
return $.inArray(event, Delegator.natives) === -1;
|
||||
};
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var Range,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Range = {};
|
||||
|
||||
Range.sniff = function(r) {
|
||||
if (r.commonAncestorContainer != null) {
|
||||
return new Range.BrowserRange(r);
|
||||
} else if (typeof r.start === "string") {
|
||||
return new Range.SerializedRange(r);
|
||||
} else if (r.start && typeof r.start === "object") {
|
||||
return new Range.NormalizedRange(r);
|
||||
} else {
|
||||
console.error(_t("Could not sniff range type"));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Range.nodeFromXPath = function(xpath, root) {
|
||||
var customResolver, evaluateXPath, namespace, node, segment;
|
||||
if (root == null) {
|
||||
root = document;
|
||||
}
|
||||
evaluateXPath = function(xp, nsResolver) {
|
||||
var exception;
|
||||
if (nsResolver == null) {
|
||||
nsResolver = null;
|
||||
}
|
||||
try {
|
||||
return document.evaluate('.' + xp, root, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
||||
} catch (_error) {
|
||||
exception = _error;
|
||||
console.log("XPath evaluation failed.");
|
||||
console.log("Trying fallback...");
|
||||
return Util.nodeFromXPath(xp, root);
|
||||
}
|
||||
};
|
||||
if (!$.isXMLDoc(document.documentElement)) {
|
||||
return evaluateXPath(xpath);
|
||||
} else {
|
||||
customResolver = document.createNSResolver(document.ownerDocument === null ? document.documentElement : document.ownerDocument.documentElement);
|
||||
node = evaluateXPath(xpath, customResolver);
|
||||
if (!node) {
|
||||
xpath = ((function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = xpath.split('/');
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
segment = _ref[_i];
|
||||
if (segment && segment.indexOf(':') === -1) {
|
||||
_results.push(segment.replace(/^([a-z]+)/, 'xhtml:$1'));
|
||||
} else {
|
||||
_results.push(segment);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})()).join('/');
|
||||
namespace = document.lookupNamespaceURI(null);
|
||||
customResolver = function(ns) {
|
||||
if (ns === 'xhtml') {
|
||||
return namespace;
|
||||
} else {
|
||||
return document.documentElement.getAttribute('xmlns:' + ns);
|
||||
}
|
||||
};
|
||||
node = evaluateXPath(xpath, customResolver);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
Range.RangeError = (function(_super) {
|
||||
__extends(RangeError, _super);
|
||||
|
||||
function RangeError(type, message, parent) {
|
||||
this.type = type;
|
||||
this.message = message;
|
||||
this.parent = parent != null ? parent : null;
|
||||
RangeError.__super__.constructor.call(this, this.message);
|
||||
}
|
||||
|
||||
return RangeError;
|
||||
|
||||
})(Error);
|
||||
|
||||
Range.BrowserRange = (function() {
|
||||
function BrowserRange(obj) {
|
||||
this.commonAncestorContainer = obj.commonAncestorContainer;
|
||||
this.startContainer = obj.startContainer;
|
||||
this.startOffset = obj.startOffset;
|
||||
this.endContainer = obj.endContainer;
|
||||
this.endOffset = obj.endOffset;
|
||||
}
|
||||
|
||||
BrowserRange.prototype.normalize = function(root) {
|
||||
var n, node, nr, r;
|
||||
if (this.tainted) {
|
||||
console.error(_t("You may only call normalize() once on a BrowserRange!"));
|
||||
return false;
|
||||
} else {
|
||||
this.tainted = true;
|
||||
}
|
||||
r = {};
|
||||
if (this.startContainer.nodeType === Node.ELEMENT_NODE) {
|
||||
r.start = Util.getFirstTextNodeNotBefore(this.startContainer.childNodes[this.startOffset]);
|
||||
r.startOffset = 0;
|
||||
} else {
|
||||
r.start = this.startContainer;
|
||||
r.startOffset = this.startOffset;
|
||||
}
|
||||
if (this.endContainer.nodeType === Node.ELEMENT_NODE) {
|
||||
node = this.endContainer.childNodes[this.endOffset];
|
||||
if (node != null) {
|
||||
n = node;
|
||||
while ((n != null) && (n.nodeType !== Node.TEXT_NODE)) {
|
||||
n = n.firstChild;
|
||||
}
|
||||
if (n != null) {
|
||||
r.end = n;
|
||||
r.endOffset = 0;
|
||||
}
|
||||
}
|
||||
if (r.end == null) {
|
||||
node = this.endContainer.childNodes[this.endOffset - 1];
|
||||
r.end = Util.getLastTextNodeUpTo(node);
|
||||
r.endOffset = r.end.nodeValue.length;
|
||||
}
|
||||
} else {
|
||||
r.end = this.endContainer;
|
||||
r.endOffset = this.endOffset;
|
||||
}
|
||||
nr = {};
|
||||
if (r.startOffset > 0) {
|
||||
if (r.start.nodeValue.length > r.startOffset) {
|
||||
nr.start = r.start.splitText(r.startOffset);
|
||||
} else {
|
||||
nr.start = r.start.nextSibling;
|
||||
}
|
||||
} else {
|
||||
nr.start = r.start;
|
||||
}
|
||||
if (r.start === r.end) {
|
||||
if (nr.start.nodeValue.length > (r.endOffset - r.startOffset)) {
|
||||
nr.start.splitText(r.endOffset - r.startOffset);
|
||||
}
|
||||
nr.end = nr.start;
|
||||
} else {
|
||||
if (r.end.nodeValue.length > r.endOffset) {
|
||||
r.end.splitText(r.endOffset);
|
||||
}
|
||||
nr.end = r.end;
|
||||
}
|
||||
nr.commonAncestor = this.commonAncestorContainer;
|
||||
while (nr.commonAncestor.nodeType !== Node.ELEMENT_NODE) {
|
||||
nr.commonAncestor = nr.commonAncestor.parentNode;
|
||||
}
|
||||
return new Range.NormalizedRange(nr);
|
||||
};
|
||||
|
||||
BrowserRange.prototype.serialize = function(root, ignoreSelector) {
|
||||
return this.normalize(root).serialize(root, ignoreSelector);
|
||||
};
|
||||
|
||||
return BrowserRange;
|
||||
|
||||
})();
|
||||
|
||||
Range.NormalizedRange = (function() {
|
||||
function NormalizedRange(obj) {
|
||||
this.commonAncestor = obj.commonAncestor;
|
||||
this.start = obj.start;
|
||||
this.end = obj.end;
|
||||
}
|
||||
|
||||
NormalizedRange.prototype.normalize = function(root) {
|
||||
return this;
|
||||
};
|
||||
|
||||
NormalizedRange.prototype.limit = function(bounds) {
|
||||
var nodes, parent, startParents, _i, _len, _ref;
|
||||
nodes = $.grep(this.textNodes(), function(node) {
|
||||
return node.parentNode === bounds || $.contains(bounds, node.parentNode);
|
||||
});
|
||||
if (!nodes.length) {
|
||||
return null;
|
||||
}
|
||||
this.start = nodes[0];
|
||||
this.end = nodes[nodes.length - 1];
|
||||
startParents = $(this.start).parents();
|
||||
_ref = $(this.end).parents();
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
parent = _ref[_i];
|
||||
if (startParents.index(parent) !== -1) {
|
||||
this.commonAncestor = parent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
NormalizedRange.prototype.serialize = function(root, ignoreSelector) {
|
||||
var end, serialization, start;
|
||||
serialization = function(node, isEnd) {
|
||||
var n, nodes, offset, origParent, textNodes, xpath, _i, _len;
|
||||
if (ignoreSelector) {
|
||||
origParent = $(node).parents(":not(" + ignoreSelector + ")").eq(0);
|
||||
} else {
|
||||
origParent = $(node).parent();
|
||||
}
|
||||
xpath = Util.xpathFromNode(origParent, root)[0];
|
||||
textNodes = Util.getTextNodes(origParent);
|
||||
nodes = textNodes.slice(0, textNodes.index(node));
|
||||
offset = 0;
|
||||
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
|
||||
n = nodes[_i];
|
||||
offset += n.nodeValue.length;
|
||||
}
|
||||
if (isEnd) {
|
||||
return [xpath, offset + node.nodeValue.length];
|
||||
} else {
|
||||
return [xpath, offset];
|
||||
}
|
||||
};
|
||||
start = serialization(this.start);
|
||||
end = serialization(this.end, true);
|
||||
return new Range.SerializedRange({
|
||||
start: start[0],
|
||||
end: end[0],
|
||||
startOffset: start[1],
|
||||
endOffset: end[1]
|
||||
});
|
||||
};
|
||||
|
||||
NormalizedRange.prototype.text = function() {
|
||||
var node;
|
||||
return ((function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = this.textNodes();
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
node = _ref[_i];
|
||||
_results.push(node.nodeValue);
|
||||
}
|
||||
return _results;
|
||||
}).call(this)).join('');
|
||||
};
|
||||
|
||||
NormalizedRange.prototype.textNodes = function() {
|
||||
var end, start, textNodes, _ref;
|
||||
textNodes = Util.getTextNodes($(this.commonAncestor));
|
||||
_ref = [textNodes.index(this.start), textNodes.index(this.end)], start = _ref[0], end = _ref[1];
|
||||
return $.makeArray(textNodes.slice(start, +end + 1 || 9e9));
|
||||
};
|
||||
|
||||
NormalizedRange.prototype.toRange = function() {
|
||||
var range;
|
||||
range = document.createRange();
|
||||
range.setStartBefore(this.start);
|
||||
range.setEndAfter(this.end);
|
||||
return range;
|
||||
};
|
||||
|
||||
return NormalizedRange;
|
||||
|
||||
})();
|
||||
|
||||
Range.SerializedRange = (function() {
|
||||
function SerializedRange(obj) {
|
||||
this.start = obj.start;
|
||||
this.startOffset = obj.startOffset;
|
||||
this.end = obj.end;
|
||||
this.endOffset = obj.endOffset;
|
||||
}
|
||||
|
||||
SerializedRange.prototype.normalize = function(root) {
|
||||
var contains, e, length, node, p, range, targetOffset, tn, _i, _j, _len, _len1, _ref, _ref1;
|
||||
range = {};
|
||||
_ref = ['start', 'end'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
p = _ref[_i];
|
||||
try {
|
||||
node = Range.nodeFromXPath(this[p], root);
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
throw new Range.RangeError(p, ("Error while finding " + p + " node: " + this[p] + ": ") + e, e);
|
||||
}
|
||||
if (!node) {
|
||||
throw new Range.RangeError(p, "Couldn't find " + p + " node: " + this[p]);
|
||||
}
|
||||
length = 0;
|
||||
targetOffset = this[p + 'Offset'];
|
||||
if (p === 'end') {
|
||||
targetOffset--;
|
||||
}
|
||||
_ref1 = Util.getTextNodes($(node));
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
tn = _ref1[_j];
|
||||
if (length + tn.nodeValue.length > targetOffset) {
|
||||
range[p + 'Container'] = tn;
|
||||
range[p + 'Offset'] = this[p + 'Offset'] - length;
|
||||
break;
|
||||
} else {
|
||||
length += tn.nodeValue.length;
|
||||
}
|
||||
}
|
||||
if (range[p + 'Offset'] == null) {
|
||||
throw new Range.RangeError("" + p + "offset", "Couldn't find offset " + this[p + 'Offset'] + " in element " + this[p]);
|
||||
}
|
||||
}
|
||||
contains = document.compareDocumentPosition == null ? function(a, b) {
|
||||
return a.contains(b);
|
||||
} : function(a, b) {
|
||||
return a.compareDocumentPosition(b) & 16;
|
||||
};
|
||||
$(range.startContainer).parents().each(function() {
|
||||
if (contains(this, range.endContainer)) {
|
||||
range.commonAncestorContainer = this;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return new Range.BrowserRange(range).normalize(root);
|
||||
};
|
||||
|
||||
SerializedRange.prototype.serialize = function(root, ignoreSelector) {
|
||||
return this.normalize(root).serialize(root, ignoreSelector);
|
||||
};
|
||||
|
||||
SerializedRange.prototype.toObject = function() {
|
||||
return {
|
||||
start: this.start,
|
||||
startOffset: this.startOffset,
|
||||
end: this.end,
|
||||
endOffset: this.endOffset
|
||||
};
|
||||
};
|
||||
|
||||
return SerializedRange;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var Annotator, g, _Annotator, _ref,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
_Annotator = this.Annotator;
|
||||
|
||||
Annotator = (function(_super) {
|
||||
__extends(Annotator, _super);
|
||||
|
||||
Annotator.prototype.events = {
|
||||
".annotator-adder button click": "onAdderClick",
|
||||
".annotator-adder button mousedown": "onAdderMousedown",
|
||||
".annotator-hl mouseover": "onHighlightMouseover",
|
||||
".annotator-hl mouseout": "startViewerHideTimer"
|
||||
};
|
||||
|
||||
Annotator.prototype.html = {
|
||||
adder: '<div class="annotator-adder"><button>' + _t('Annotate') + '</button></div>',
|
||||
wrapper: '<div class="annotator-wrapper"></div>'
|
||||
};
|
||||
|
||||
Annotator.prototype.options = {
|
||||
readOnly: false
|
||||
};
|
||||
|
||||
Annotator.prototype.plugins = {};
|
||||
|
||||
Annotator.prototype.editor = null;
|
||||
|
||||
Annotator.prototype.viewer = null;
|
||||
|
||||
Annotator.prototype.selectedRanges = null;
|
||||
|
||||
Annotator.prototype.mouseIsDown = false;
|
||||
|
||||
Annotator.prototype.ignoreMouseup = false;
|
||||
|
||||
Annotator.prototype.viewerHideTimer = null;
|
||||
|
||||
function Annotator(element, options) {
|
||||
this.onDeleteAnnotation = __bind(this.onDeleteAnnotation, this);
|
||||
this.onEditAnnotation = __bind(this.onEditAnnotation, this);
|
||||
this.onAdderClick = __bind(this.onAdderClick, this);
|
||||
this.onAdderMousedown = __bind(this.onAdderMousedown, this);
|
||||
this.onHighlightMouseover = __bind(this.onHighlightMouseover, this);
|
||||
this.checkForEndSelection = __bind(this.checkForEndSelection, this);
|
||||
this.checkForStartSelection = __bind(this.checkForStartSelection, this);
|
||||
this.clearViewerHideTimer = __bind(this.clearViewerHideTimer, this);
|
||||
this.startViewerHideTimer = __bind(this.startViewerHideTimer, this);
|
||||
this.showViewer = __bind(this.showViewer, this);
|
||||
this.onEditorSubmit = __bind(this.onEditorSubmit, this);
|
||||
this.onEditorHide = __bind(this.onEditorHide, this);
|
||||
this.showEditor = __bind(this.showEditor, this);
|
||||
Annotator.__super__.constructor.apply(this, arguments);
|
||||
this.plugins = {};
|
||||
if (!Annotator.supported()) {
|
||||
return this;
|
||||
}
|
||||
if (!this.options.readOnly) {
|
||||
this._setupDocumentEvents();
|
||||
}
|
||||
this._setupWrapper()._setupViewer()._setupEditor();
|
||||
this._setupDynamicStyle();
|
||||
this.adder = $(this.html.adder).appendTo(this.wrapper).hide();
|
||||
Annotator._instances.push(this);
|
||||
}
|
||||
|
||||
Annotator.prototype._setupWrapper = function() {
|
||||
this.wrapper = $(this.html.wrapper);
|
||||
this.element.find('script').remove();
|
||||
this.element.wrapInner(this.wrapper);
|
||||
this.wrapper = this.element.find('.annotator-wrapper');
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype._setupViewer = function() {
|
||||
var _this = this;
|
||||
this.viewer = new Annotator.Viewer({
|
||||
readOnly: this.options.readOnly
|
||||
});
|
||||
this.viewer.hide().on("edit", this.onEditAnnotation).on("delete", this.onDeleteAnnotation).addField({
|
||||
load: function(field, annotation) {
|
||||
if (annotation.text) {
|
||||
$(field).html(Util.escape(annotation.text));
|
||||
} else {
|
||||
$(field).html("<i>" + (_t('No Comment')) + "</i>");
|
||||
}
|
||||
return _this.publish('annotationViewerTextField', [field, annotation]);
|
||||
}
|
||||
}).element.appendTo(this.wrapper).bind({
|
||||
"mouseover": this.clearViewerHideTimer,
|
||||
"mouseout": this.startViewerHideTimer
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype._setupEditor = function() {
|
||||
this.editor = new Annotator.Editor();
|
||||
this.editor.hide().on('hide', this.onEditorHide).on('save', this.onEditorSubmit).addField({
|
||||
type: 'textarea',
|
||||
label: _t('Comments') + '\u2026',
|
||||
load: function(field, annotation) {
|
||||
return $(field).find('textarea').val(annotation.text || '');
|
||||
},
|
||||
submit: function(field, annotation) {
|
||||
return annotation.text = $(field).find('textarea').val();
|
||||
}
|
||||
});
|
||||
this.editor.element.appendTo(this.wrapper);
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype._setupDocumentEvents = function() {
|
||||
$(document).bind({
|
||||
"mouseup": this.checkForEndSelection,
|
||||
"mousedown": this.checkForStartSelection
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype._setupDynamicStyle = function() {
|
||||
var max, sel, style, x;
|
||||
style = $('#annotator-dynamic-style');
|
||||
if (!style.length) {
|
||||
style = $('<style id="annotator-dynamic-style"></style>').appendTo(document.head);
|
||||
}
|
||||
sel = '*' + ((function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = ['adder', 'outer', 'notice', 'filter'];
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
x = _ref[_i];
|
||||
_results.push(":not(.annotator-" + x + ")");
|
||||
}
|
||||
return _results;
|
||||
})()).join('');
|
||||
max = Util.maxZIndex($(document.body).find(sel));
|
||||
max = Math.max(max, 1000);
|
||||
style.text([".annotator-adder, .annotator-outer, .annotator-notice {", " z-index: " + (max + 20) + ";", "}", ".annotator-filter {", " z-index: " + (max + 10) + ";", "}"].join("\n"));
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype.destroy = function() {
|
||||
var idx, name, plugin, _ref;
|
||||
$(document).unbind({
|
||||
"mouseup": this.checkForEndSelection,
|
||||
"mousedown": this.checkForStartSelection
|
||||
});
|
||||
$('#annotator-dynamic-style').remove();
|
||||
this.adder.remove();
|
||||
this.viewer.destroy();
|
||||
this.editor.destroy();
|
||||
this.wrapper.find('.annotator-hl').each(function() {
|
||||
$(this).contents().insertBefore(this);
|
||||
return $(this).remove();
|
||||
});
|
||||
this.wrapper.contents().insertBefore(this.wrapper);
|
||||
this.wrapper.remove();
|
||||
this.element.data('annotator', null);
|
||||
_ref = this.plugins;
|
||||
for (name in _ref) {
|
||||
plugin = _ref[name];
|
||||
this.plugins[name].destroy();
|
||||
}
|
||||
this.removeEvents();
|
||||
idx = Annotator._instances.indexOf(this);
|
||||
if (idx !== -1) {
|
||||
return Annotator._instances.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
|
||||
Annotator.prototype.getSelectedRanges = function() {
|
||||
var browserRange, i, normedRange, r, ranges, rangesToIgnore, selection, _i, _len;
|
||||
selection = Util.getGlobal().getSelection();
|
||||
ranges = [];
|
||||
rangesToIgnore = [];
|
||||
if (!selection.isCollapsed) {
|
||||
ranges = (function() {
|
||||
var _i, _ref, _results;
|
||||
_results = [];
|
||||
for (i = _i = 0, _ref = selection.rangeCount; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
r = selection.getRangeAt(i);
|
||||
browserRange = new Range.BrowserRange(r);
|
||||
normedRange = browserRange.normalize().limit(this.wrapper[0]);
|
||||
if (normedRange === null) {
|
||||
rangesToIgnore.push(r);
|
||||
}
|
||||
_results.push(normedRange);
|
||||
}
|
||||
return _results;
|
||||
}).call(this);
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
for (_i = 0, _len = rangesToIgnore.length; _i < _len; _i++) {
|
||||
r = rangesToIgnore[_i];
|
||||
selection.addRange(r);
|
||||
}
|
||||
return $.grep(ranges, function(range) {
|
||||
if (range) {
|
||||
selection.addRange(range.toRange());
|
||||
}
|
||||
return range;
|
||||
});
|
||||
};
|
||||
|
||||
Annotator.prototype.createAnnotation = function() {
|
||||
var annotation;
|
||||
annotation = {};
|
||||
this.publish('beforeAnnotationCreated', [annotation]);
|
||||
return annotation;
|
||||
};
|
||||
|
||||
Annotator.prototype.setupAnnotation = function(annotation) {
|
||||
var e, normed, normedRanges, r, root, _i, _j, _len, _len1, _ref;
|
||||
root = this.wrapper[0];
|
||||
annotation.ranges || (annotation.ranges = this.selectedRanges);
|
||||
normedRanges = [];
|
||||
_ref = annotation.ranges;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
r = _ref[_i];
|
||||
try {
|
||||
normedRanges.push(Range.sniff(r).normalize(root));
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
if (e instanceof Range.RangeError) {
|
||||
this.publish('rangeNormalizeFail', [annotation, r, e]);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (normedRanges.length!=0){
|
||||
annotation.quote = [];
|
||||
annotation.ranges = [];
|
||||
annotation.highlights = [];
|
||||
for (_j = 0, _len1 = normedRanges.length; _j < _len1; _j++) {
|
||||
normed = normedRanges[_j];
|
||||
annotation.quote.push($.trim(normed.text()));
|
||||
annotation.ranges.push(normed.serialize(this.wrapper[0], '.annotator-hl'));
|
||||
$.merge(annotation.highlights, this.highlightRange(normed));
|
||||
}
|
||||
annotation.quote = annotation.quote.join(' / ');
|
||||
$(annotation.highlights).data('annotation', annotation);
|
||||
}
|
||||
return annotation;
|
||||
};
|
||||
|
||||
Annotator.prototype.updateAnnotation = function(annotation) {
|
||||
this.publish('beforeAnnotationUpdated', [annotation]);
|
||||
this.publish('annotationUpdated', [annotation]);
|
||||
return annotation;
|
||||
};
|
||||
|
||||
Annotator.prototype.deleteAnnotation = function(annotation) {
|
||||
var child, h, _i, _len, _ref;
|
||||
if (annotation.highlights != null) {
|
||||
_ref = annotation.highlights;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
h = _ref[_i];
|
||||
if (!(h.parentNode != null)) {
|
||||
continue;
|
||||
}
|
||||
child = h.childNodes[0];
|
||||
$(h).replaceWith(h.childNodes);
|
||||
}
|
||||
}
|
||||
this.publish('annotationDeleted', [annotation]);
|
||||
return annotation;
|
||||
};
|
||||
|
||||
Annotator.prototype.loadAnnotations = function(annotations) {
|
||||
var clone, loader,
|
||||
_this = this;
|
||||
if (annotations == null) {
|
||||
annotations = [];
|
||||
}
|
||||
loader = function(annList) {
|
||||
var n, now, _i, _len;
|
||||
if (annList == null) {
|
||||
annList = [];
|
||||
}
|
||||
now = annList.splice(0, 10);
|
||||
for (_i = 0, _len = now.length; _i < _len; _i++) {
|
||||
n = now[_i];
|
||||
_this.setupAnnotation(n);
|
||||
}
|
||||
if (annList.length > 0) {
|
||||
return setTimeout((function() {
|
||||
return loader(annList);
|
||||
}), 10);
|
||||
} else {
|
||||
return _this.publish('annotationsLoaded', [clone]);
|
||||
}
|
||||
};
|
||||
clone = annotations.slice();
|
||||
loader(annotations);
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype.dumpAnnotations = function() {
|
||||
if (this.plugins['Store']) {
|
||||
return this.plugins['Store'].dumpAnnotations();
|
||||
} else {
|
||||
console.warn(_t("Can't dump annotations without Store plugin."));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Annotator.prototype.highlightRange = function(normedRange, cssClass) {
|
||||
var hl, node, white, _i, _len, _ref, _results;
|
||||
if (cssClass == null) {
|
||||
cssClass = 'annotator-hl';
|
||||
}
|
||||
white = /^\s*$/;
|
||||
hl = $("<span class='" + cssClass + "'></span>");
|
||||
_ref = normedRange.textNodes();
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
node = _ref[_i];
|
||||
if (!white.test(node.nodeValue)) {
|
||||
_results.push($(node).wrapAll(hl).parent().show()[0]);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Annotator.prototype.highlightRanges = function(normedRanges, cssClass) {
|
||||
var highlights, r, _i, _len;
|
||||
if (cssClass == null) {
|
||||
cssClass = 'annotator-hl';
|
||||
}
|
||||
highlights = [];
|
||||
for (_i = 0, _len = normedRanges.length; _i < _len; _i++) {
|
||||
r = normedRanges[_i];
|
||||
$.merge(highlights, this.highlightRange(r, cssClass));
|
||||
}
|
||||
return highlights;
|
||||
};
|
||||
|
||||
Annotator.prototype.addPlugin = function(name, options) {
|
||||
var klass, _base;
|
||||
if (this.plugins[name]) {
|
||||
console.error(_t("You cannot have more than one instance of any plugin."));
|
||||
} else {
|
||||
klass = Annotator.Plugin[name];
|
||||
if (typeof klass === 'function') {
|
||||
this.plugins[name] = new klass(this.element[0], options);
|
||||
this.plugins[name].annotator = this;
|
||||
if (typeof (_base = this.plugins[name]).pluginInit === "function") {
|
||||
_base.pluginInit();
|
||||
}
|
||||
} else {
|
||||
console.error(_t("Could not load ") + name + _t(" plugin. Have you included the appropriate <script> tag?"));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype.showEditor = function(annotation, location) {
|
||||
this.editor.element.css(location);
|
||||
this.editor.load(annotation);
|
||||
this.publish('annotationEditorShown', [this.editor, annotation]);
|
||||
return this;
|
||||
};
|
||||
|
||||
Annotator.prototype.onEditorHide = function() {
|
||||
this.publish('annotationEditorHidden', [this.editor]);
|
||||
return this.ignoreMouseup = false;
|
||||
};
|
||||
|
||||
Annotator.prototype.onEditorSubmit = function(annotation) {
|
||||
return this.publish('annotationEditorSubmit', [this.editor, annotation]);
|
||||
};
|
||||
|
||||
Annotator.prototype.showViewer = function(annotations, location) {
|
||||
this.viewer.element.css(location);
|
||||
this.viewer.load(annotations);
|
||||
return this.publish('annotationViewerShown', [this.viewer, annotations]);
|
||||
};
|
||||
|
||||
Annotator.prototype.startViewerHideTimer = function() {
|
||||
if (!this.viewerHideTimer) {
|
||||
return this.viewerHideTimer = setTimeout(this.viewer.hide, 250);
|
||||
}
|
||||
};
|
||||
|
||||
Annotator.prototype.clearViewerHideTimer = function() {
|
||||
clearTimeout(this.viewerHideTimer);
|
||||
return this.viewerHideTimer = false;
|
||||
};
|
||||
|
||||
Annotator.prototype.checkForStartSelection = function(event) {
|
||||
if (!(event && this.isAnnotator(event.target))) {
|
||||
this.startViewerHideTimer();
|
||||
}
|
||||
return this.mouseIsDown = true;
|
||||
};
|
||||
|
||||
Annotator.prototype.checkForEndSelection = function(event) {
|
||||
var container, range, _i, _len, _ref;
|
||||
this.mouseIsDown = false;
|
||||
if (this.ignoreMouseup) {
|
||||
return;
|
||||
}
|
||||
this.selectedRanges = this.getSelectedRanges();
|
||||
_ref = this.selectedRanges;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
range = _ref[_i];
|
||||
container = range.commonAncestor;
|
||||
if ($(container).hasClass('annotator-hl')) {
|
||||
container = $(container).parents('[class!=annotator-hl]')[0];
|
||||
}
|
||||
if (this.isAnnotator(container)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (event && this.selectedRanges.length) {
|
||||
return this.adder.css(Util.mousePosition(event, this.wrapper[0])).show();
|
||||
} else {
|
||||
return this.adder.hide();
|
||||
}
|
||||
};
|
||||
|
||||
Annotator.prototype.isAnnotator = function(element) {
|
||||
return !!$(element).parents().addBack().filter('[class^=annotator-]').not(this.wrapper).length;
|
||||
};
|
||||
|
||||
Annotator.prototype.onHighlightMouseover = function(event) {
|
||||
var annotations;
|
||||
this.clearViewerHideTimer();
|
||||
if (this.mouseIsDown || this.viewer.isShown()) {
|
||||
return false;
|
||||
}
|
||||
annotations = $(event.target).parents('.annotator-hl').addBack().map(function() {
|
||||
return $(this).data("annotation");
|
||||
});
|
||||
return this.showViewer($.makeArray(annotations), Util.mousePosition(event, this.wrapper[0]));
|
||||
};
|
||||
|
||||
Annotator.prototype.onAdderMousedown = function(event) {
|
||||
if (event != null) {
|
||||
event.preventDefault();
|
||||
}
|
||||
return this.ignoreMouseup = true;
|
||||
};
|
||||
|
||||
Annotator.prototype.onAdderClick = function(event) {
|
||||
var annotation, cancel, cleanup, position, save,
|
||||
_this = this;
|
||||
if (event != null) {
|
||||
event.preventDefault();
|
||||
}
|
||||
position = this.adder.position();
|
||||
this.adder.hide();
|
||||
annotation = this.setupAnnotation(this.createAnnotation());
|
||||
$(annotation.highlights).addClass('annotator-hl-temporary');
|
||||
save = function() {
|
||||
cleanup();
|
||||
$(annotation.highlights).removeClass('annotator-hl-temporary');
|
||||
return _this.publish('annotationCreated', [annotation]);
|
||||
};
|
||||
cancel = function() {
|
||||
cleanup();
|
||||
return _this.deleteAnnotation(annotation);
|
||||
};
|
||||
cleanup = function() {
|
||||
_this.unsubscribe('annotationEditorHidden', cancel);
|
||||
return _this.unsubscribe('annotationEditorSubmit', save);
|
||||
};
|
||||
this.subscribe('annotationEditorHidden', cancel);
|
||||
this.subscribe('annotationEditorSubmit', save);
|
||||
return this.showEditor(annotation, position);
|
||||
};
|
||||
|
||||
Annotator.prototype.onEditAnnotation = function(annotation) {
|
||||
var cleanup, offset, update,
|
||||
_this = this;
|
||||
offset = this.viewer.element.position();
|
||||
update = function() {
|
||||
cleanup();
|
||||
return _this.updateAnnotation(annotation);
|
||||
};
|
||||
cleanup = function() {
|
||||
_this.unsubscribe('annotationEditorHidden', cleanup);
|
||||
return _this.unsubscribe('annotationEditorSubmit', update);
|
||||
};
|
||||
this.subscribe('annotationEditorHidden', cleanup);
|
||||
this.subscribe('annotationEditorSubmit', update);
|
||||
this.viewer.hide();
|
||||
return this.showEditor(annotation, offset);
|
||||
};
|
||||
|
||||
Annotator.prototype.onDeleteAnnotation = function(annotation) {
|
||||
this.viewer.hide();
|
||||
return this.deleteAnnotation(annotation);
|
||||
};
|
||||
|
||||
return Annotator;
|
||||
|
||||
})(Delegator);
|
||||
|
||||
Annotator.Plugin = (function(_super) {
|
||||
__extends(Plugin, _super);
|
||||
|
||||
function Plugin(element, options) {
|
||||
Plugin.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Plugin.prototype.pluginInit = function() {};
|
||||
|
||||
Plugin.prototype.destroy = function() {
|
||||
return this.removeEvents();
|
||||
};
|
||||
|
||||
return Plugin;
|
||||
|
||||
})(Delegator);
|
||||
|
||||
g = Util.getGlobal();
|
||||
|
||||
if (((_ref = g.document) != null ? _ref.evaluate : void 0) == null) {
|
||||
$.getScript('//assets.annotateit.org/vendor/xpath.min.js');
|
||||
}
|
||||
|
||||
if (g.getSelection == null) {
|
||||
$.getScript('//assets.annotateit.org/vendor/ierange.min.js');
|
||||
}
|
||||
|
||||
if (g.JSON == null) {
|
||||
$.getScript('//assets.annotateit.org/vendor/json2.min.js');
|
||||
}
|
||||
|
||||
if (g.Node == null) {
|
||||
g.Node = {
|
||||
ELEMENT_NODE: 1,
|
||||
ATTRIBUTE_NODE: 2,
|
||||
TEXT_NODE: 3,
|
||||
CDATA_SECTION_NODE: 4,
|
||||
ENTITY_REFERENCE_NODE: 5,
|
||||
ENTITY_NODE: 6,
|
||||
PROCESSING_INSTRUCTION_NODE: 7,
|
||||
COMMENT_NODE: 8,
|
||||
DOCUMENT_NODE: 9,
|
||||
DOCUMENT_TYPE_NODE: 10,
|
||||
DOCUMENT_FRAGMENT_NODE: 11,
|
||||
NOTATION_NODE: 12
|
||||
};
|
||||
}
|
||||
|
||||
Annotator.$ = $;
|
||||
|
||||
Annotator.Delegator = Delegator;
|
||||
|
||||
Annotator.Range = Range;
|
||||
|
||||
Annotator.Util = Util;
|
||||
|
||||
Annotator._instances = [];
|
||||
|
||||
Annotator._t = _t;
|
||||
|
||||
Annotator.supported = function() {
|
||||
return (function() {
|
||||
return !!this.getSelection;
|
||||
})();
|
||||
};
|
||||
|
||||
Annotator.noConflict = function() {
|
||||
Util.getGlobal().Annotator = _Annotator;
|
||||
return this;
|
||||
};
|
||||
|
||||
$.fn.annotator = function(options) {
|
||||
var args;
|
||||
args = Array.prototype.slice.call(arguments, 1);
|
||||
var temp = this.each(function() {
|
||||
var instance;
|
||||
instance = $.data(this, 'annotator');
|
||||
if (instance) {
|
||||
return options && instance[options].apply(instance, args);
|
||||
} else {
|
||||
instance = new Annotator(this, options);
|
||||
return $.data(this, 'annotator', instance);
|
||||
}
|
||||
});
|
||||
return temp;
|
||||
};
|
||||
|
||||
this.Annotator = Annotator;
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var __hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Widget = (function(_super) {
|
||||
__extends(Widget, _super);
|
||||
|
||||
Widget.prototype.classes = {
|
||||
hide: 'annotator-hide',
|
||||
invert: {
|
||||
x: 'annotator-invert-x',
|
||||
y: 'annotator-invert-y'
|
||||
}
|
||||
};
|
||||
|
||||
function Widget(element, options) {
|
||||
Widget.__super__.constructor.apply(this, arguments);
|
||||
this.classes = $.extend({}, Annotator.Widget.prototype.classes, this.classes);
|
||||
}
|
||||
|
||||
Widget.prototype.destroy = function() {
|
||||
this.removeEvents();
|
||||
return this.element.remove();
|
||||
};
|
||||
|
||||
Widget.prototype.checkOrientation = function() {
|
||||
var current, offset, viewport, widget, window;
|
||||
this.resetOrientation();
|
||||
window = $(Annotator.Util.getGlobal());
|
||||
widget = this.element.children(":first");
|
||||
offset = widget.offset();
|
||||
viewport = {
|
||||
top: window.scrollTop(),
|
||||
right: window.width() + window.scrollLeft()
|
||||
};
|
||||
current = {
|
||||
top: offset.top,
|
||||
right: offset.left + widget.width()
|
||||
};
|
||||
if ((current.top - viewport.top) < 0) {
|
||||
this.invertY();
|
||||
}
|
||||
if ((current.right - viewport.right) > 0) {
|
||||
this.invertX();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Widget.prototype.resetOrientation = function() {
|
||||
this.element.removeClass(this.classes.invert.x).removeClass(this.classes.invert.y);
|
||||
return this;
|
||||
};
|
||||
|
||||
Widget.prototype.invertX = function() {
|
||||
this.element.addClass(this.classes.invert.x);
|
||||
return this;
|
||||
};
|
||||
|
||||
Widget.prototype.invertY = function() {
|
||||
this.element.addClass(this.classes.invert.y);
|
||||
return this;
|
||||
};
|
||||
|
||||
Widget.prototype.isInvertedY = function() {
|
||||
return this.element.hasClass(this.classes.invert.y);
|
||||
};
|
||||
|
||||
Widget.prototype.isInvertedX = function() {
|
||||
return this.element.hasClass(this.classes.invert.x);
|
||||
};
|
||||
|
||||
return Widget;
|
||||
|
||||
})(Delegator);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Editor = (function(_super) {
|
||||
__extends(Editor, _super);
|
||||
|
||||
Editor.prototype.events = {
|
||||
"form submit": "submit",
|
||||
".annotator-save click": "submit",
|
||||
".annotator-cancel click": "hide",
|
||||
".annotator-cancel mouseover": "onCancelButtonMouseover",
|
||||
"textarea keydown": "processKeypress"
|
||||
};
|
||||
|
||||
Editor.prototype.classes = {
|
||||
hide: 'annotator-hide',
|
||||
focus: 'annotator-focus'
|
||||
};
|
||||
|
||||
Editor.prototype.html = "<div class=\"annotator-outer annotator-editor\">\n <form class=\"annotator-widget\">\n <ul class=\"annotator-listing\"></ul>\n <div class=\"annotator-controls\">\n <a href=\"#cancel\" class=\"annotator-cancel\">" + _t('Cancel') + "</a>\n<a href=\"#save\" class=\"annotator-save annotator-focus\">" + _t('Save') + "</a>\n </div>\n </form>\n</div>";
|
||||
|
||||
Editor.prototype.options = {};
|
||||
|
||||
function Editor(options) {
|
||||
this.onCancelButtonMouseover = __bind(this.onCancelButtonMouseover, this);
|
||||
this.processKeypress = __bind(this.processKeypress, this);
|
||||
this.submit = __bind(this.submit, this);
|
||||
this.load = __bind(this.load, this);
|
||||
this.hide = __bind(this.hide, this);
|
||||
this.show = __bind(this.show, this);
|
||||
Editor.__super__.constructor.call(this, $(this.html)[0], options);
|
||||
this.fields = [];
|
||||
this.annotation = {};
|
||||
}
|
||||
|
||||
Editor.prototype.show = function(event) {
|
||||
Annotator.Util.preventEventDefault(event);
|
||||
this.element.removeClass(this.classes.hide);
|
||||
this.element.find('.annotator-save').addClass(this.classes.focus);
|
||||
this.checkOrientation();
|
||||
this.element.find(":input:first").focus();
|
||||
this.setupDraggables();
|
||||
return this.publish('show');
|
||||
};
|
||||
|
||||
Editor.prototype.hide = function(event) {
|
||||
Annotator.Util.preventEventDefault(event);
|
||||
this.element.addClass(this.classes.hide);
|
||||
return this.publish('hide');
|
||||
};
|
||||
|
||||
Editor.prototype.load = function(annotation) {
|
||||
var field, _i, _len, _ref;
|
||||
this.annotation = annotation;
|
||||
this.publish('load', [this.annotation]);
|
||||
_ref = this.fields;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
field = _ref[_i];
|
||||
field.load(field.element, this.annotation);
|
||||
}
|
||||
return this.show();
|
||||
};
|
||||
|
||||
Editor.prototype.submit = function(event) {
|
||||
var field, _i, _len, _ref;
|
||||
Annotator.Util.preventEventDefault(event);
|
||||
_ref = this.fields;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
field = _ref[_i];
|
||||
field.submit(field.element, this.annotation);
|
||||
}
|
||||
this.publish('save', [this.annotation]);
|
||||
return this.hide();
|
||||
};
|
||||
|
||||
Editor.prototype.addField = function(options) {
|
||||
var element, field, input;
|
||||
field = $.extend({
|
||||
id: 'annotator-field-' + Annotator.Util.uuid(),
|
||||
type: 'input',
|
||||
label: '',
|
||||
load: function() {},
|
||||
submit: function() {}
|
||||
}, options);
|
||||
input = null;
|
||||
element = $('<li class="annotator-item" />');
|
||||
field.element = element[0];
|
||||
switch (field.type) {
|
||||
case 'textarea':
|
||||
input = $('<textarea />');
|
||||
break;
|
||||
case 'input':
|
||||
case 'checkbox':
|
||||
input = $('<input />');
|
||||
break;
|
||||
case 'select':
|
||||
input = $('<select />');
|
||||
}
|
||||
element.append(input);
|
||||
input.attr({
|
||||
id: field.id,
|
||||
placeholder: field.label
|
||||
});
|
||||
if (field.type === 'checkbox') {
|
||||
input[0].type = 'checkbox';
|
||||
element.addClass('annotator-checkbox');
|
||||
element.append($('<label />', {
|
||||
"for": field.id,
|
||||
html: field.label
|
||||
}));
|
||||
}
|
||||
this.element.find('ul:first').append(element);
|
||||
this.fields.push(field);
|
||||
return field.element;
|
||||
};
|
||||
|
||||
Editor.prototype.checkOrientation = function() {
|
||||
var controls, list;
|
||||
Editor.__super__.checkOrientation.apply(this, arguments);
|
||||
list = this.element.find('.annotator-listing');
|
||||
controls = this.element.find('.annotator-controls');
|
||||
if (this.element.hasClass(this.classes.invert.y)) {
|
||||
controls.insertBefore(list);
|
||||
} else if (controls.is(':first-child')) {
|
||||
controls.insertAfter(list);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Editor.prototype.processKeypress = function(event) {
|
||||
if (event.keyCode === 27) {
|
||||
return this.hide();
|
||||
} else if (event.keyCode === 13 && !event.shiftKey) {
|
||||
return this.submit();
|
||||
}
|
||||
};
|
||||
|
||||
Editor.prototype.onCancelButtonMouseover = function() {
|
||||
return this.element.find('.' + this.classes.focus).removeClass(this.classes.focus);
|
||||
};
|
||||
|
||||
Editor.prototype.setupDraggables = function() {
|
||||
var classes, controls, cornerItem, editor, mousedown, onMousedown, onMousemove, onMouseup, resize, textarea, throttle,
|
||||
_this = this;
|
||||
this.element.find('.annotator-resize').remove();
|
||||
if (this.element.hasClass(this.classes.invert.y)) {
|
||||
cornerItem = this.element.find('.annotator-item:last');
|
||||
} else {
|
||||
cornerItem = this.element.find('.annotator-item:first');
|
||||
}
|
||||
if (cornerItem) {
|
||||
$('<span class="annotator-resize"></span>').appendTo(cornerItem);
|
||||
}
|
||||
mousedown = null;
|
||||
classes = this.classes;
|
||||
editor = this.element;
|
||||
textarea = null;
|
||||
resize = editor.find('.annotator-resize');
|
||||
controls = editor.find('.annotator-controls');
|
||||
throttle = false;
|
||||
onMousedown = function(event) {
|
||||
if (event.target === this) {
|
||||
mousedown = {
|
||||
element: this,
|
||||
top: event.pageY,
|
||||
left: event.pageX
|
||||
};
|
||||
textarea = editor.find('textarea:first');
|
||||
$(window).bind({
|
||||
'mouseup.annotator-editor-resize': onMouseup,
|
||||
'mousemove.annotator-editor-resize': onMousemove
|
||||
});
|
||||
return event.preventDefault();
|
||||
}
|
||||
};
|
||||
onMouseup = function() {
|
||||
mousedown = null;
|
||||
return $(window).unbind('.annotator-editor-resize');
|
||||
};
|
||||
onMousemove = function(event) {
|
||||
var diff, directionX, directionY, height, width;
|
||||
if (mousedown && throttle === false) {
|
||||
diff = {
|
||||
top: event.pageY - mousedown.top,
|
||||
left: event.pageX - mousedown.left
|
||||
};
|
||||
if (mousedown.element === resize[0]) {
|
||||
height = textarea.outerHeight();
|
||||
width = textarea.outerWidth();
|
||||
directionX = editor.hasClass(classes.invert.x) ? -1 : 1;
|
||||
directionY = editor.hasClass(classes.invert.y) ? 1 : -1;
|
||||
textarea.height(height + (diff.top * directionY));
|
||||
textarea.width(width + (diff.left * directionX));
|
||||
if (textarea.outerHeight() !== height) {
|
||||
mousedown.top = event.pageY;
|
||||
}
|
||||
if (textarea.outerWidth() !== width) {
|
||||
mousedown.left = event.pageX;
|
||||
}
|
||||
} else if (mousedown.element === controls[0]) {
|
||||
editor.css({
|
||||
top: parseInt(editor.css('top'), 10) + diff.top,
|
||||
left: parseInt(editor.css('left'), 10) + diff.left
|
||||
});
|
||||
mousedown.top = event.pageY;
|
||||
mousedown.left = event.pageX;
|
||||
}
|
||||
throttle = true;
|
||||
return setTimeout(function() {
|
||||
return throttle = false;
|
||||
}, 1000 / 60);
|
||||
}
|
||||
};
|
||||
resize.bind('mousedown', onMousedown);
|
||||
return controls.bind('mousedown', onMousedown);
|
||||
};
|
||||
|
||||
return Editor;
|
||||
|
||||
})(Annotator.Widget);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var LinkParser,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Viewer = (function(_super) {
|
||||
__extends(Viewer, _super);
|
||||
|
||||
Viewer.prototype.events = {
|
||||
".annotator-edit click": "onEditClick",
|
||||
".annotator-delete click": "onDeleteClick"
|
||||
};
|
||||
|
||||
Viewer.prototype.classes = {
|
||||
hide: 'annotator-hide',
|
||||
showControls: 'annotator-visible'
|
||||
};
|
||||
|
||||
Viewer.prototype.html = {
|
||||
element: "<div class=\"annotator-outer annotator-viewer\">\n <ul class=\"annotator-widget annotator-listing\"></ul>\n</div>",
|
||||
item: "<li class=\"annotator-annotation annotator-item\">\n <span class=\"annotator-controls\">\n <a href=\"#\" title=\"View as webpage\" class=\"annotator-link\">View as webpage</a>\n <button title=\"Edit\" class=\"annotator-edit\">Edit</button>\n <button title=\"Delete\" class=\"annotator-delete\">Delete</button>\n </span>\n</li>"
|
||||
};
|
||||
|
||||
Viewer.prototype.options = {
|
||||
readOnly: false
|
||||
};
|
||||
|
||||
function Viewer(options) {
|
||||
this.onDeleteClick = __bind(this.onDeleteClick, this);
|
||||
this.onEditClick = __bind(this.onEditClick, this);
|
||||
this.load = __bind(this.load, this);
|
||||
this.hide = __bind(this.hide, this);
|
||||
this.show = __bind(this.show, this);
|
||||
Viewer.__super__.constructor.call(this, $(this.html.element)[0], options);
|
||||
this.item = $(this.html.item)[0];
|
||||
this.fields = [];
|
||||
this.annotations = [];
|
||||
}
|
||||
|
||||
Viewer.prototype.show = function(event) {
|
||||
var controls,
|
||||
_this = this;
|
||||
Annotator.Util.preventEventDefault(event);
|
||||
controls = this.element.find('.annotator-controls').addClass(this.classes.showControls);
|
||||
setTimeout((function() {
|
||||
return controls.removeClass(_this.classes.showControls);
|
||||
}), 500);
|
||||
this.element.removeClass(this.classes.hide);
|
||||
return this.checkOrientation().publish('show');
|
||||
};
|
||||
|
||||
Viewer.prototype.isShown = function() {
|
||||
return !this.element.hasClass(this.classes.hide);
|
||||
};
|
||||
|
||||
Viewer.prototype.hide = function(event) {
|
||||
Annotator.Util.preventEventDefault(event);
|
||||
this.element.addClass(this.classes.hide);
|
||||
return this.publish('hide');
|
||||
};
|
||||
|
||||
Viewer.prototype.load = function(annotations) {
|
||||
var annotation, controller, controls, del, edit, element, field, item, link, links, list, _i, _j, _len, _len1, _ref, _ref1;
|
||||
this.annotations = annotations || [];
|
||||
list = this.element.find('ul:first').empty();
|
||||
_ref = this.annotations;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
annotation = _ref[_i];
|
||||
item = $(this.item).clone().appendTo(list).data('annotation', annotation);
|
||||
controls = item.find('.annotator-controls');
|
||||
link = controls.find('.annotator-link');
|
||||
edit = controls.find('.annotator-edit');
|
||||
del = controls.find('.annotator-delete');
|
||||
links = new LinkParser(annotation.links || []).get('alternate', {
|
||||
'type': 'text/html'
|
||||
});
|
||||
if (links.length === 0 || (links[0].href == null)) {
|
||||
link.remove();
|
||||
} else {
|
||||
link.attr('href', links[0].href);
|
||||
}
|
||||
if (this.options.readOnly) {
|
||||
edit.remove();
|
||||
del.remove();
|
||||
} else {
|
||||
controller = {
|
||||
showEdit: function() {
|
||||
return edit.removeAttr('disabled');
|
||||
},
|
||||
hideEdit: function() {
|
||||
return edit.attr('disabled', 'disabled');
|
||||
},
|
||||
showDelete: function() {
|
||||
return del.removeAttr('disabled');
|
||||
},
|
||||
hideDelete: function() {
|
||||
return del.attr('disabled', 'disabled');
|
||||
}
|
||||
};
|
||||
}
|
||||
_ref1 = this.fields;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
field = _ref1[_j];
|
||||
element = $(field.element).clone().appendTo(item)[0];
|
||||
field.load(element, annotation, controller);
|
||||
}
|
||||
}
|
||||
this.publish('load', [this.annotations]);
|
||||
return this.show();
|
||||
};
|
||||
|
||||
Viewer.prototype.addField = function(options) {
|
||||
var field;
|
||||
field = $.extend({
|
||||
load: function() {}
|
||||
}, options);
|
||||
field.element = $('<div />')[0];
|
||||
this.fields.push(field);
|
||||
field.element;
|
||||
return this;
|
||||
};
|
||||
|
||||
Viewer.prototype.onEditClick = function(event) {
|
||||
return this.onButtonClick(event, 'edit');
|
||||
};
|
||||
|
||||
Viewer.prototype.onDeleteClick = function(event) {
|
||||
return this.onButtonClick(event, 'delete');
|
||||
};
|
||||
|
||||
Viewer.prototype.onButtonClick = function(event, type) {
|
||||
var item;
|
||||
item = $(event.target).parents('.annotator-annotation');
|
||||
return this.publish(type, [item.data('annotation')]);
|
||||
};
|
||||
|
||||
return Viewer;
|
||||
|
||||
})(Annotator.Widget);
|
||||
|
||||
LinkParser = (function() {
|
||||
function LinkParser(data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
LinkParser.prototype.get = function(rel, cond) {
|
||||
var d, k, keys, match, v, _i, _len, _ref, _results;
|
||||
if (cond == null) {
|
||||
cond = {};
|
||||
}
|
||||
cond = $.extend({}, cond, {
|
||||
rel: rel
|
||||
});
|
||||
keys = (function() {
|
||||
var _results;
|
||||
_results = [];
|
||||
for (k in cond) {
|
||||
if (!__hasProp.call(cond, k)) continue;
|
||||
v = cond[k];
|
||||
_results.push(k);
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
_ref = this.data;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
d = _ref[_i];
|
||||
match = keys.reduce((function(m, k) {
|
||||
return m && (d[k] === cond[k]);
|
||||
}), true);
|
||||
if (match) {
|
||||
_results.push(d);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
return LinkParser;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var Annotator,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator = Annotator || {};
|
||||
|
||||
Annotator.Notification = (function(_super) {
|
||||
__extends(Notification, _super);
|
||||
|
||||
Notification.prototype.events = {
|
||||
"click": "hide"
|
||||
};
|
||||
|
||||
Notification.prototype.options = {
|
||||
html: "<div class='annotator-notice'></div>",
|
||||
classes: {
|
||||
show: "annotator-notice-show",
|
||||
info: "annotator-notice-info",
|
||||
success: "annotator-notice-success",
|
||||
error: "annotator-notice-error"
|
||||
}
|
||||
};
|
||||
|
||||
function Notification(options) {
|
||||
this.hide = __bind(this.hide, this);
|
||||
this.show = __bind(this.show, this);
|
||||
Notification.__super__.constructor.call(this, $(this.options.html).appendTo(document.body)[0], options);
|
||||
}
|
||||
|
||||
Notification.prototype.show = function(message, status) {
|
||||
if (status == null) {
|
||||
status = Annotator.Notification.INFO;
|
||||
}
|
||||
this.currentStatus = status;
|
||||
$(this.element).addClass(this.options.classes.show).addClass(this.options.classes[this.currentStatus]).html(Util.escape(message || ""));
|
||||
setTimeout(this.hide, 5000);
|
||||
return this;
|
||||
};
|
||||
|
||||
Notification.prototype.hide = function() {
|
||||
if (this.currentStatus == null) {
|
||||
this.currentStatus = Annotator.Notification.INFO;
|
||||
}
|
||||
$(this.element).removeClass(this.options.classes.show).removeClass(this.options.classes[this.currentStatus]);
|
||||
return this;
|
||||
};
|
||||
|
||||
return Notification;
|
||||
|
||||
})(Delegator);
|
||||
|
||||
Annotator.Notification.INFO = 'info';
|
||||
|
||||
Annotator.Notification.SUCCESS = 'success';
|
||||
|
||||
Annotator.Notification.ERROR = 'error';
|
||||
|
||||
$(function() {
|
||||
var notification;
|
||||
notification = new Annotator.Notification;
|
||||
Annotator.showNotification = notification.show;
|
||||
return Annotator.hideNotification = notification.hide;
|
||||
});
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var _ref,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Unsupported = (function(_super) {
|
||||
__extends(Unsupported, _super);
|
||||
|
||||
function Unsupported() {
|
||||
_ref = Unsupported.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
Unsupported.prototype.options = {
|
||||
message: Annotator._t("Sorry your current browser does not support the Annotator")
|
||||
};
|
||||
|
||||
Unsupported.prototype.pluginInit = function() {
|
||||
var _this = this;
|
||||
if (!Annotator.supported()) {
|
||||
return $(function() {
|
||||
Annotator.showNotification(_this.options.message);
|
||||
if ((window.XMLHttpRequest === void 0) && (ActiveXObject !== void 0)) {
|
||||
return $('html').addClass('ie6');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Unsupported;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var base64Decode, base64UrlDecode, createDateFromISO8601, parseToken,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
createDateFromISO8601 = function(string) {
|
||||
var d, date, offset, regexp, time, _ref;
|
||||
regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\\.([0-9]+))?)?" + "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
|
||||
d = string.match(new RegExp(regexp));
|
||||
offset = 0;
|
||||
date = new Date(d[1], 0, 1);
|
||||
if (d[3]) {
|
||||
date.setMonth(d[3] - 1);
|
||||
}
|
||||
if (d[5]) {
|
||||
date.setDate(d[5]);
|
||||
}
|
||||
if (d[7]) {
|
||||
date.setHours(d[7]);
|
||||
}
|
||||
if (d[8]) {
|
||||
date.setMinutes(d[8]);
|
||||
}
|
||||
if (d[10]) {
|
||||
date.setSeconds(d[10]);
|
||||
}
|
||||
if (d[12]) {
|
||||
date.setMilliseconds(Number("0." + d[12]) * 1000);
|
||||
}
|
||||
if (d[14]) {
|
||||
offset = (Number(d[16]) * 60) + Number(d[17]);
|
||||
offset *= (_ref = d[15] === '-') != null ? _ref : {
|
||||
1: -1
|
||||
};
|
||||
}
|
||||
offset -= date.getTimezoneOffset();
|
||||
time = Number(date) + (offset * 60 * 1000);
|
||||
date.setTime(Number(time));
|
||||
return date;
|
||||
};
|
||||
|
||||
base64Decode = function(data) {
|
||||
var ac, b64, bits, dec, h1, h2, h3, h4, i, o1, o2, o3, tmp_arr;
|
||||
if (typeof atob !== "undefined" && atob !== null) {
|
||||
return atob(data);
|
||||
} else {
|
||||
b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
i = 0;
|
||||
ac = 0;
|
||||
dec = "";
|
||||
tmp_arr = [];
|
||||
if (!data) {
|
||||
return data;
|
||||
}
|
||||
data += '';
|
||||
while (i < data.length) {
|
||||
h1 = b64.indexOf(data.charAt(i++));
|
||||
h2 = b64.indexOf(data.charAt(i++));
|
||||
h3 = b64.indexOf(data.charAt(i++));
|
||||
h4 = b64.indexOf(data.charAt(i++));
|
||||
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
|
||||
o1 = bits >> 16 & 0xff;
|
||||
o2 = bits >> 8 & 0xff;
|
||||
o3 = bits & 0xff;
|
||||
if (h3 === 64) {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1);
|
||||
} else if (h4 === 64) {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1, o2);
|
||||
} else {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
|
||||
}
|
||||
}
|
||||
return tmp_arr.join('');
|
||||
}
|
||||
};
|
||||
|
||||
base64UrlDecode = function(data) {
|
||||
var i, m, _i, _ref;
|
||||
m = data.length % 4;
|
||||
if (m !== 0) {
|
||||
for (i = _i = 0, _ref = 4 - m; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
data += '=';
|
||||
}
|
||||
}
|
||||
data = data.replace(/-/g, '+');
|
||||
data = data.replace(/_/g, '/');
|
||||
return base64Decode(data);
|
||||
};
|
||||
|
||||
parseToken = function(token) {
|
||||
var head, payload, sig, _ref;
|
||||
_ref = token.split('.'), head = _ref[0], payload = _ref[1], sig = _ref[2];
|
||||
return JSON.parse(base64UrlDecode(payload));
|
||||
};
|
||||
|
||||
Annotator.Plugin.Auth = (function(_super) {
|
||||
__extends(Auth, _super);
|
||||
|
||||
Auth.prototype.options = {
|
||||
token: null,
|
||||
tokenUrl: '/auth/token',
|
||||
autoFetch: true
|
||||
};
|
||||
|
||||
function Auth(element, options) {
|
||||
Auth.__super__.constructor.apply(this, arguments);
|
||||
this.waitingForToken = [];
|
||||
if (this.options.token) {
|
||||
this.setToken(this.options.token);
|
||||
} else {
|
||||
this.requestToken();
|
||||
}
|
||||
}
|
||||
|
||||
Auth.prototype.requestToken = function() {
|
||||
var _this = this;
|
||||
this.requestInProgress = true;
|
||||
return $.ajax({
|
||||
url: this.options.tokenUrl,
|
||||
dataType: 'text',
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
}
|
||||
}).done(function(data, status, xhr) {
|
||||
return _this.setToken(data);
|
||||
}).fail(function(xhr, status, err) {
|
||||
var msg;
|
||||
msg = Annotator._t("Couldn't get auth token:");
|
||||
console.error("" + msg + " " + err, xhr);
|
||||
return Annotator.showNotification("" + msg + " " + xhr.responseText, Annotator.Notification.ERROR);
|
||||
}).always(function() {
|
||||
return _this.requestInProgress = false;
|
||||
});
|
||||
};
|
||||
|
||||
Auth.prototype.setToken = function(token) {
|
||||
var _results,
|
||||
_this = this;
|
||||
this.token = token;
|
||||
this._unsafeToken = parseToken(token);
|
||||
if (this.haveValidToken()) {
|
||||
if (this.options.autoFetch) {
|
||||
this.refreshTimeout = setTimeout((function() {
|
||||
return _this.requestToken();
|
||||
}), (this.timeToExpiry() - 2) * 1000);
|
||||
}
|
||||
this.updateHeaders();
|
||||
_results = [];
|
||||
while (this.waitingForToken.length > 0) {
|
||||
_results.push(this.waitingForToken.pop()(this._unsafeToken));
|
||||
}
|
||||
return _results;
|
||||
} else {
|
||||
console.warn(Annotator._t("Didn't get a valid token."));
|
||||
if (this.options.autoFetch) {
|
||||
console.warn(Annotator._t("Getting a new token in 10s."));
|
||||
return setTimeout((function() {
|
||||
return _this.requestToken();
|
||||
}), 10 * 1000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Auth.prototype.haveValidToken = function() {
|
||||
var allFields;
|
||||
allFields = this._unsafeToken && this._unsafeToken.issuedAt && this._unsafeToken.ttl && this._unsafeToken.consumerKey;
|
||||
if (allFields && this.timeToExpiry() > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Auth.prototype.timeToExpiry = function() {
|
||||
var expiry, issue, now, timeToExpiry;
|
||||
now = new Date().getTime() / 1000;
|
||||
issue = createDateFromISO8601(this._unsafeToken.issuedAt).getTime() / 1000;
|
||||
expiry = issue + this._unsafeToken.ttl;
|
||||
timeToExpiry = expiry - now;
|
||||
if (timeToExpiry > 0) {
|
||||
return timeToExpiry;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
Auth.prototype.updateHeaders = function() {
|
||||
var current;
|
||||
current = this.element.data('annotator:headers');
|
||||
return this.element.data('annotator:headers', $.extend(current, {
|
||||
'x-annotator-auth-token': this.token
|
||||
}));
|
||||
};
|
||||
|
||||
Auth.prototype.withToken = function(callback) {
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
if (this.haveValidToken()) {
|
||||
return callback(this._unsafeToken);
|
||||
} else {
|
||||
this.waitingForToken.push(callback);
|
||||
if (!this.requestInProgress) {
|
||||
return this.requestToken();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Auth;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
Annotator.Plugin.Store = (function(_super) {
|
||||
__extends(Store, _super);
|
||||
|
||||
Store.prototype.events = {
|
||||
'annotationCreated': 'annotationCreated',
|
||||
'annotationDeleted': 'annotationDeleted',
|
||||
'annotationUpdated': 'annotationUpdated'
|
||||
};
|
||||
|
||||
Store.prototype.options = {
|
||||
annotationData: {},
|
||||
emulateHTTP: false,
|
||||
loadFromSearch: false,
|
||||
prefix: '/store',
|
||||
urls: {
|
||||
create: '/annotations',
|
||||
read: '/annotations/:id',
|
||||
update: '/annotations/:id',
|
||||
destroy: '/annotations/:id',
|
||||
search: '/search'
|
||||
}
|
||||
};
|
||||
|
||||
function Store(element, options) {
|
||||
this._onError = __bind(this._onError, this);
|
||||
this._onLoadAnnotationsFromSearch = __bind(this._onLoadAnnotationsFromSearch, this);
|
||||
this._onLoadAnnotations = __bind(this._onLoadAnnotations, this);
|
||||
this._getAnnotations = __bind(this._getAnnotations, this);
|
||||
Store.__super__.constructor.apply(this, arguments);
|
||||
this.annotations = [];
|
||||
}
|
||||
|
||||
Store.prototype.pluginInit = function() {
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
if (this.annotator.plugins.Auth) {
|
||||
return this.annotator.plugins.Auth.withToken(this._getAnnotations);
|
||||
} else {
|
||||
return this._getAnnotations();
|
||||
}
|
||||
};
|
||||
|
||||
Store.prototype._getAnnotations = function() {
|
||||
if (this.options.loadFromSearch) {
|
||||
return this.loadAnnotationsFromSearch(this.options.loadFromSearch);
|
||||
} else {
|
||||
return this.loadAnnotations();
|
||||
}
|
||||
};
|
||||
|
||||
Store.prototype.annotationCreated = function(annotation) {
|
||||
var _this = this;
|
||||
if (__indexOf.call(this.annotations, annotation) < 0) {
|
||||
this.registerAnnotation(annotation);
|
||||
return this._apiRequest('create', annotation, function(data) {
|
||||
if (data.id == null) {
|
||||
console.warn(Annotator._t("Warning: No ID returned from server for annotation "), annotation);
|
||||
}
|
||||
return _this.updateAnnotation(annotation, data);
|
||||
});
|
||||
} else {
|
||||
return this.updateAnnotation(annotation, {});
|
||||
}
|
||||
};
|
||||
|
||||
Store.prototype.annotationUpdated = function(annotation) {
|
||||
var _this = this;
|
||||
if (__indexOf.call(this.annotations, annotation) >= 0) {
|
||||
return this._apiRequest('update', annotation, (function(data) {
|
||||
return _this.updateAnnotation(annotation, data);
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
Store.prototype.annotationDeleted = function(annotation) {
|
||||
var _this = this;
|
||||
if (__indexOf.call(this.annotations, annotation) >= 0) {
|
||||
return this._apiRequest('destroy', annotation, (function() {
|
||||
return _this.unregisterAnnotation(annotation);
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
Store.prototype.registerAnnotation = function(annotation) {
|
||||
return this.annotations.push(annotation);
|
||||
};
|
||||
|
||||
Store.prototype.unregisterAnnotation = function(annotation) {
|
||||
return this.annotations.splice(this.annotations.indexOf(annotation), 1);
|
||||
};
|
||||
|
||||
Store.prototype.updateAnnotation = function(annotation, data) {
|
||||
if (__indexOf.call(this.annotations, annotation) < 0) {
|
||||
console.error(Annotator._t("Trying to update unregistered annotation!"));
|
||||
} else {
|
||||
$.extend(annotation, data);
|
||||
}
|
||||
return $(annotation.highlights).data('annotation', annotation);
|
||||
};
|
||||
|
||||
Store.prototype.loadAnnotations = function() {
|
||||
return this._apiRequest('read', null, this._onLoadAnnotations);
|
||||
};
|
||||
|
||||
Store.prototype._onLoadAnnotations = function(data) {
|
||||
var a, annotation, annotationMap, newData, _i, _j, _len, _len1, _ref;
|
||||
if (data == null) {
|
||||
data = [];
|
||||
}
|
||||
annotationMap = {};
|
||||
_ref = this.annotations;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
a = _ref[_i];
|
||||
annotationMap[a.id] = a;
|
||||
}
|
||||
newData = [];
|
||||
for (_j = 0, _len1 = data.length; _j < _len1; _j++) {
|
||||
a = data[_j];
|
||||
if (annotationMap[a.id]) {
|
||||
annotation = annotationMap[a.id];
|
||||
this.updateAnnotation(annotation, a);
|
||||
} else {
|
||||
newData.push(a);
|
||||
}
|
||||
}
|
||||
this.annotations = this.annotations.concat(newData);
|
||||
return this.annotator.loadAnnotations(newData.slice());
|
||||
};
|
||||
|
||||
Store.prototype.loadAnnotationsFromSearch = function(searchOptions) {
|
||||
return this._apiRequest('search', searchOptions, this._onLoadAnnotationsFromSearch);
|
||||
};
|
||||
|
||||
Store.prototype._onLoadAnnotationsFromSearch = function(data) {
|
||||
if (data == null) {
|
||||
data = {};
|
||||
}
|
||||
return this._onLoadAnnotations(data.rows || []);
|
||||
};
|
||||
|
||||
Store.prototype.dumpAnnotations = function() {
|
||||
var ann, _i, _len, _ref, _results;
|
||||
_ref = this.annotations;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
ann = _ref[_i];
|
||||
_results.push(JSON.parse(this._dataFor(ann)));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Store.prototype._apiRequest = function(action, obj, onSuccess) {
|
||||
var id, options, request, url;
|
||||
id = obj && obj.id;
|
||||
url = this._urlFor(action, id);
|
||||
options = this._apiRequestOptions(action, obj, onSuccess);
|
||||
request = $.ajax(url, options);
|
||||
request._id = id;
|
||||
request._action = action;
|
||||
return request;
|
||||
};
|
||||
|
||||
Store.prototype._apiRequestOptions = function(action, obj, onSuccess) {
|
||||
var data, method, opts;
|
||||
method = this._methodFor(action);
|
||||
opts = {
|
||||
type: method,
|
||||
headers: this.element.data('annotator:headers'),
|
||||
dataType: "json",
|
||||
success: onSuccess || function() {},
|
||||
error: this._onError
|
||||
};
|
||||
if (this.options.emulateHTTP && (method === 'PUT' || method === 'DELETE')) {
|
||||
opts.headers = $.extend(opts.headers, {
|
||||
'X-HTTP-Method-Override': method
|
||||
});
|
||||
opts.type = 'POST';
|
||||
}
|
||||
if (action === "search") {
|
||||
opts = $.extend(opts, {
|
||||
data: obj
|
||||
});
|
||||
return opts;
|
||||
}
|
||||
data = obj && this._dataFor(obj);
|
||||
if (this.options.emulateJSON) {
|
||||
opts.data = {
|
||||
json: data
|
||||
};
|
||||
if (this.options.emulateHTTP) {
|
||||
opts.data._method = method;
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
opts = $.extend(opts, {
|
||||
data: data,
|
||||
contentType: "application/json; charset=utf-8"
|
||||
});
|
||||
return opts;
|
||||
};
|
||||
|
||||
Store.prototype._urlFor = function(action, id) {
|
||||
var url;
|
||||
url = this.options.prefix != null ? this.options.prefix : '';
|
||||
url += this.options.urls[action];
|
||||
url = url.replace(/\/:id/, id != null ? '/' + id : '');
|
||||
url = url.replace(/:id/, id != null ? id : '');
|
||||
return url;
|
||||
};
|
||||
|
||||
Store.prototype._methodFor = function(action) {
|
||||
var table;
|
||||
table = {
|
||||
'create': 'POST',
|
||||
'read': 'GET',
|
||||
'update': 'PUT',
|
||||
'destroy': 'DELETE',
|
||||
'search': 'GET'
|
||||
};
|
||||
return table[action];
|
||||
};
|
||||
|
||||
Store.prototype._dataFor = function(annotation) {
|
||||
var data, highlights;
|
||||
highlights = annotation.highlights;
|
||||
delete annotation.highlights;
|
||||
$.extend(annotation, this.options.annotationData);
|
||||
data = JSON.stringify(annotation);
|
||||
if (highlights) {
|
||||
annotation.highlights = highlights;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
Store.prototype._onError = function(xhr) {
|
||||
var action, message;
|
||||
action = xhr._action;
|
||||
message = Annotator._t("Sorry, our server seems to be down. We could not ") + action + Annotator._t(" this annotation");
|
||||
if (xhr._action === 'search') {
|
||||
message = Annotator._t("Sorry, the Annotations service is down. Contact your instructor and try again later.");
|
||||
} else if (xhr._action === 'read' && !xhr._id) {
|
||||
message = Annotator._t("Sorry, our server seems to be down. We could not ") + action + Annotator._t(" the annotation(s).");
|
||||
}
|
||||
switch (xhr.status) {
|
||||
case 401:
|
||||
message = Annotator._t("Sorry, you are not allowed to ") + action + Annotator._t(" this annotation");
|
||||
break;
|
||||
case 404:
|
||||
message = Annotator._t("Sorry, we could not connect to the annotations database.");
|
||||
break;
|
||||
case 500:
|
||||
message = Annotator._t("Sorry, our server is down. Contact your instructor and try again later.");
|
||||
}
|
||||
Annotator.showNotification(message, Annotator.Notification.ERROR);
|
||||
return console.error(Annotator._t("API request failed:") + (" '" + xhr.status + "'"));
|
||||
};
|
||||
|
||||
return Store;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Permissions = (function(_super) {
|
||||
__extends(Permissions, _super);
|
||||
|
||||
Permissions.prototype.events = {
|
||||
'beforeAnnotationCreated': 'addFieldsToAnnotation'
|
||||
};
|
||||
|
||||
Permissions.prototype.options = {
|
||||
showViewPermissionsCheckbox: true,
|
||||
showEditPermissionsCheckbox: true,
|
||||
userId: function(user) {
|
||||
return user;
|
||||
},
|
||||
userString: function(user) {
|
||||
return user;
|
||||
},
|
||||
userAuthorize: function(action, annotation, user) {
|
||||
var token, tokens, _i, _len;
|
||||
if (annotation.permissions) {
|
||||
tokens = annotation.permissions[action] || [];
|
||||
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;
|
||||
},
|
||||
user: '',
|
||||
permissions: {
|
||||
'read': [],
|
||||
'update': [],
|
||||
'delete': [],
|
||||
'admin': []
|
||||
}
|
||||
};
|
||||
|
||||
function Permissions(element, options) {
|
||||
this._setAuthFromToken = __bind(this._setAuthFromToken, this);
|
||||
this.updateViewer = __bind(this.updateViewer, this);
|
||||
this.updateAnnotationPermissions = __bind(this.updateAnnotationPermissions, this);
|
||||
this.updatePermissionsField = __bind(this.updatePermissionsField, this);
|
||||
this.addFieldsToAnnotation = __bind(this.addFieldsToAnnotation, this);
|
||||
Permissions.__super__.constructor.apply(this, arguments);
|
||||
if (this.options.user) {
|
||||
this.setUser(this.options.user);
|
||||
delete this.options.user;
|
||||
}
|
||||
}
|
||||
|
||||
Permissions.prototype.pluginInit = function() {
|
||||
var createCallback, self,
|
||||
_this = this;
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
self = this;
|
||||
createCallback = function(method, type) {
|
||||
return function(field, annotation) {
|
||||
return self[method].call(self, type, field, annotation);
|
||||
};
|
||||
};
|
||||
if (!this.user && this.annotator.plugins.Auth) {
|
||||
this.annotator.plugins.Auth.withToken(this._setAuthFromToken);
|
||||
}
|
||||
if (this.options.showViewPermissionsCheckbox === true) {
|
||||
this.annotator.editor.addField({
|
||||
type: 'checkbox',
|
||||
label: Annotator._t('Allow anyone to <strong>view</strong> this annotation'),
|
||||
load: createCallback('updatePermissionsField', 'read'),
|
||||
submit: createCallback('updateAnnotationPermissions', 'read')
|
||||
});
|
||||
}
|
||||
if (this.options.showEditPermissionsCheckbox === true) {
|
||||
this.annotator.editor.addField({
|
||||
type: 'checkbox',
|
||||
label: Annotator._t('Allow anyone to <strong>edit</strong> this annotation'),
|
||||
load: createCallback('updatePermissionsField', 'update'),
|
||||
submit: createCallback('updateAnnotationPermissions', 'update')
|
||||
});
|
||||
}
|
||||
this.annotator.viewer.addField({
|
||||
load: this.updateViewer
|
||||
});
|
||||
if (this.annotator.plugins.Filter) {
|
||||
return this.annotator.plugins.Filter.addFilter({
|
||||
label: Annotator._t('User'),
|
||||
property: 'user',
|
||||
isFiltered: function(input, user) {
|
||||
var keyword, _i, _len, _ref;
|
||||
user = _this.options.userString(user);
|
||||
if (!(input && user)) {
|
||||
return false;
|
||||
}
|
||||
_ref = input.split(/\s*/);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
keyword = _ref[_i];
|
||||
if (user.indexOf(keyword) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Permissions.prototype.setUser = function(user) {
|
||||
return this.user = user;
|
||||
};
|
||||
|
||||
Permissions.prototype.addFieldsToAnnotation = function(annotation) {
|
||||
if (annotation) {
|
||||
annotation.permissions = this.options.permissions;
|
||||
if (this.user) {
|
||||
return annotation.user = this.user;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Permissions.prototype.authorize = function(action, annotation, user) {
|
||||
if (user === void 0) {
|
||||
user = this.user;
|
||||
}
|
||||
if (this.options.userAuthorize) {
|
||||
return this.options.userAuthorize.call(this.options, action, annotation, user);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Permissions.prototype.updatePermissionsField = function(action, field, annotation) {
|
||||
var input;
|
||||
field = $(field).show();
|
||||
input = field.find('input').removeAttr('disabled');
|
||||
if (!this.authorize('admin', annotation)) {
|
||||
field.hide();
|
||||
}
|
||||
if (this.authorize(action, annotation || {}, null)) {
|
||||
return input.attr('checked', 'checked');
|
||||
} else {
|
||||
return input.removeAttr('checked');
|
||||
}
|
||||
};
|
||||
|
||||
Permissions.prototype.updateAnnotationPermissions = function(type, field, annotation) {
|
||||
var dataKey;
|
||||
if (!annotation.permissions) {
|
||||
annotation.permissions = this.options.permissions;
|
||||
}
|
||||
dataKey = type + '-permissions';
|
||||
if ($(field).find('input').is(':checked')) {
|
||||
return annotation.permissions[type] = [];
|
||||
} else {
|
||||
return annotation.permissions[type] = [this.options.userId(this.user)];
|
||||
}
|
||||
};
|
||||
|
||||
Permissions.prototype.updateViewer = function(field, annotation, controls) {
|
||||
var user, username;
|
||||
field = $(field);
|
||||
username = this.options.userString(annotation.user);
|
||||
if (annotation.user && username && typeof username === 'string') {
|
||||
user = Annotator.Util.escape(this.options.userString(annotation.user));
|
||||
field.html(user).addClass('annotator-user');
|
||||
} else {
|
||||
field.remove();
|
||||
}
|
||||
if (controls) {
|
||||
if (!this.authorize('update', annotation)) {
|
||||
controls.hideEdit();
|
||||
}
|
||||
if (!this.authorize('delete', annotation)) {
|
||||
return controls.hideDelete();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Permissions.prototype._setAuthFromToken = function(token) {
|
||||
return this.setUser(token.userId);
|
||||
};
|
||||
|
||||
return Permissions;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var _ref,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
Annotator.Plugin.AnnotateItPermissions = (function(_super) {
|
||||
__extends(AnnotateItPermissions, _super);
|
||||
|
||||
function AnnotateItPermissions() {
|
||||
this._setAuthFromToken = __bind(this._setAuthFromToken, this);
|
||||
this.updateAnnotationPermissions = __bind(this.updateAnnotationPermissions, this);
|
||||
this.updatePermissionsField = __bind(this.updatePermissionsField, this);
|
||||
this.addFieldsToAnnotation = __bind(this.addFieldsToAnnotation, this);
|
||||
_ref = AnnotateItPermissions.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
AnnotateItPermissions.prototype.options = {
|
||||
showViewPermissionsCheckbox: true,
|
||||
showEditPermissionsCheckbox: true,
|
||||
groups: {
|
||||
world: 'group:__world__',
|
||||
authenticated: 'group:__authenticated__',
|
||||
consumer: 'group:__consumer__'
|
||||
},
|
||||
userId: function(user) {
|
||||
return user.userId;
|
||||
},
|
||||
userString: function(user) {
|
||||
return user.userId;
|
||||
},
|
||||
userAuthorize: function(action, annotation, user) {
|
||||
var action_field, permissions, _ref1, _ref2, _ref3, _ref4;
|
||||
permissions = annotation.permissions || {};
|
||||
action_field = permissions[action] || [];
|
||||
if (_ref1 = this.groups.world, __indexOf.call(action_field, _ref1) >= 0) {
|
||||
return true;
|
||||
} else if ((user != null) && (user.userId != null) && (user.consumerKey != null)) {
|
||||
if (user.userId === annotation.user && user.consumerKey === annotation.consumer) {
|
||||
return true;
|
||||
} else if (_ref2 = this.groups.authenticated, __indexOf.call(action_field, _ref2) >= 0) {
|
||||
return true;
|
||||
} else if (user.consumerKey === annotation.consumer && (_ref3 = this.groups.consumer, __indexOf.call(action_field, _ref3) >= 0)) {
|
||||
return true;
|
||||
} else if (user.consumerKey === annotation.consumer && (_ref4 = user.userId, __indexOf.call(action_field, _ref4) >= 0)) {
|
||||
return true;
|
||||
} else if (user.consumerKey === annotation.consumer && user.admin) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
permissions: {
|
||||
'read': ['group:__world__'],
|
||||
'update': [],
|
||||
'delete': [],
|
||||
'admin': []
|
||||
}
|
||||
};
|
||||
|
||||
AnnotateItPermissions.prototype.addFieldsToAnnotation = function(annotation) {
|
||||
if (annotation) {
|
||||
annotation.permissions = this.options.permissions;
|
||||
if (this.user) {
|
||||
annotation.user = this.user.userId;
|
||||
return annotation.consumer = this.user.consumerKey;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AnnotateItPermissions.prototype.updatePermissionsField = function(action, field, annotation) {
|
||||
var input;
|
||||
field = $(field).show();
|
||||
input = field.find('input').removeAttr('disabled');
|
||||
if (!this.authorize('admin', annotation)) {
|
||||
field.hide();
|
||||
}
|
||||
if (this.user && this.authorize(action, annotation || {}, {
|
||||
userId: '__nonexistentuser__',
|
||||
consumerKey: this.user.consumerKey
|
||||
})) {
|
||||
return input.attr('checked', 'checked');
|
||||
} else {
|
||||
return input.removeAttr('checked');
|
||||
}
|
||||
};
|
||||
|
||||
AnnotateItPermissions.prototype.updateAnnotationPermissions = function(type, field, annotation) {
|
||||
var dataKey;
|
||||
if (!annotation.permissions) {
|
||||
annotation.permissions = this.options.permissions;
|
||||
}
|
||||
dataKey = type + '-permissions';
|
||||
if ($(field).find('input').is(':checked')) {
|
||||
return annotation.permissions[type] = [type === 'read' ? this.options.groups.world : this.options.groups.consumer];
|
||||
} else {
|
||||
return annotation.permissions[type] = [];
|
||||
}
|
||||
};
|
||||
|
||||
AnnotateItPermissions.prototype._setAuthFromToken = function(token) {
|
||||
return this.setUser(token);
|
||||
};
|
||||
|
||||
return AnnotateItPermissions;
|
||||
|
||||
})(Annotator.Plugin.Permissions);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Filter = (function(_super) {
|
||||
__extends(Filter, _super);
|
||||
|
||||
Filter.prototype.events = {
|
||||
".annotator-filter-property input focus": "_onFilterFocus",
|
||||
".annotator-filter-property input blur": "_onFilterBlur",
|
||||
".annotator-filter-property input keyup": "_onFilterKeyup",
|
||||
".annotator-filter-previous click": "_onPreviousClick",
|
||||
".annotator-filter-next click": "_onNextClick",
|
||||
".annotator-filter-clear click": "_onClearClick"
|
||||
};
|
||||
|
||||
Filter.prototype.classes = {
|
||||
active: 'annotator-filter-active',
|
||||
hl: {
|
||||
hide: 'annotator-hl-filtered',
|
||||
active: 'annotator-hl-active'
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.html = {
|
||||
element: "<div class=\"annotator-filter\">\n <strong>" + Annotator._t('Navigate:') + "</strong>\n<span class=\"annotator-filter-navigation\">\n <button class=\"annotator-filter-previous\">" + Annotator._t('Previous') + "</button>\n<button class=\"annotator-filter-next\">" + Annotator._t('Next') + "</button>\n</span>\n<strong>" + Annotator._t('Filter by:') + "</strong>\n</div>",
|
||||
filter: "<span class=\"annotator-filter-property\">\n <label></label>\n <input/>\n <button class=\"annotator-filter-clear\">" + Annotator._t('Clear') + "</button>\n</span>"
|
||||
};
|
||||
|
||||
Filter.prototype.options = {
|
||||
appendTo: 'body',
|
||||
filters: [],
|
||||
addAnnotationFilter: true,
|
||||
isFiltered: function(input, property) {
|
||||
var keyword, _i, _len, _ref;
|
||||
if (!(input && property)) {
|
||||
return false;
|
||||
}
|
||||
_ref = input.split(/\s+/);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
keyword = _ref[_i];
|
||||
if (property.indexOf(keyword) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
function Filter(element, options) {
|
||||
this._onPreviousClick = __bind(this._onPreviousClick, this);
|
||||
this._onNextClick = __bind(this._onNextClick, this);
|
||||
this._onFilterKeyup = __bind(this._onFilterKeyup, this);
|
||||
this._onFilterBlur = __bind(this._onFilterBlur, this);
|
||||
this._onFilterFocus = __bind(this._onFilterFocus, this);
|
||||
this.updateHighlights = __bind(this.updateHighlights, this);
|
||||
var _base;
|
||||
element = $(this.html.element).appendTo((options != null ? options.appendTo : void 0) || this.options.appendTo);
|
||||
Filter.__super__.constructor.call(this, element, options);
|
||||
(_base = this.options).filters || (_base.filters = []);
|
||||
this.filter = $(this.html.filter);
|
||||
this.filters = [];
|
||||
this.current = 0;
|
||||
}
|
||||
|
||||
Filter.prototype.pluginInit = function() {
|
||||
var filter, _i, _len, _ref;
|
||||
_ref = this.options.filters;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
filter = _ref[_i];
|
||||
this.addFilter(filter);
|
||||
}
|
||||
this.updateHighlights();
|
||||
this._setupListeners()._insertSpacer();
|
||||
if (this.options.addAnnotationFilter === true) {
|
||||
return this.addFilter({
|
||||
label: Annotator._t('Annotation'),
|
||||
property: 'text'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.destroy = function() {
|
||||
var currentMargin, html;
|
||||
Filter.__super__.destroy.apply(this, arguments);
|
||||
html = $('html');
|
||||
currentMargin = parseInt(html.css('padding-top'), 10) || 0;
|
||||
html.css('padding-top', currentMargin - this.element.outerHeight());
|
||||
return this.element.remove();
|
||||
};
|
||||
|
||||
Filter.prototype._insertSpacer = function() {
|
||||
var currentMargin, html;
|
||||
html = $('html');
|
||||
currentMargin = parseInt(html.css('padding-top'), 10) || 0;
|
||||
html.css('padding-top', currentMargin + this.element.outerHeight());
|
||||
return this;
|
||||
};
|
||||
|
||||
Filter.prototype._setupListeners = function() {
|
||||
var event, events, _i, _len;
|
||||
events = ['annotationsLoaded', 'annotationCreated', 'annotationUpdated', 'annotationDeleted'];
|
||||
for (_i = 0, _len = events.length; _i < _len; _i++) {
|
||||
event = events[_i];
|
||||
this.annotator.subscribe(event, this.updateHighlights);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Filter.prototype.addFilter = function(options) {
|
||||
var f, filter;
|
||||
filter = $.extend({
|
||||
label: '',
|
||||
property: '',
|
||||
isFiltered: this.options.isFiltered
|
||||
}, options);
|
||||
if (!((function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = this.filters;
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
f = _ref[_i];
|
||||
if (f.property === filter.property) {
|
||||
_results.push(f);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
}).call(this)).length) {
|
||||
filter.id = 'annotator-filter-' + filter.property;
|
||||
filter.annotations = [];
|
||||
filter.element = this.filter.clone().appendTo(this.element);
|
||||
filter.element.find('label').html(filter.label).attr('for', filter.id);
|
||||
filter.element.find('input').attr({
|
||||
id: filter.id,
|
||||
placeholder: Annotator._t('Filter by ') + filter.label + '\u2026'
|
||||
});
|
||||
filter.element.find('button').hide();
|
||||
filter.element.data('filter', filter);
|
||||
this.filters.push(filter);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Filter.prototype.updateFilter = function(filter) {
|
||||
var annotation, annotations, input, property, _i, _len, _ref;
|
||||
filter.annotations = [];
|
||||
this.updateHighlights();
|
||||
this.resetHighlights();
|
||||
input = $.trim(filter.element.find('input').val());
|
||||
if (input) {
|
||||
annotations = this.highlights.map(function() {
|
||||
return $(this).data('annotation');
|
||||
});
|
||||
_ref = $.makeArray(annotations);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
annotation = _ref[_i];
|
||||
property = annotation[filter.property];
|
||||
if (filter.isFiltered(input, property)) {
|
||||
filter.annotations.push(annotation);
|
||||
}
|
||||
}
|
||||
return this.filterHighlights();
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.updateHighlights = function() {
|
||||
this.highlights = this.annotator.element.find('.annotator-hl:visible');
|
||||
return this.filtered = this.highlights.not(this.classes.hl.hide);
|
||||
};
|
||||
|
||||
Filter.prototype.filterHighlights = function() {
|
||||
var activeFilters, annotation, annotations, filtered, highlights, index, uniques, _i, _len, _ref;
|
||||
activeFilters = $.grep(this.filters, function(filter) {
|
||||
return !!filter.annotations.length;
|
||||
});
|
||||
filtered = ((_ref = activeFilters[0]) != null ? _ref.annotations : void 0) || [];
|
||||
if (activeFilters.length > 1) {
|
||||
annotations = [];
|
||||
$.each(activeFilters, function() {
|
||||
return $.merge(annotations, this.annotations);
|
||||
});
|
||||
uniques = [];
|
||||
filtered = [];
|
||||
$.each(annotations, function() {
|
||||
if ($.inArray(this, uniques) === -1) {
|
||||
return uniques.push(this);
|
||||
} else {
|
||||
return filtered.push(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
highlights = this.highlights;
|
||||
for (index = _i = 0, _len = filtered.length; _i < _len; index = ++_i) {
|
||||
annotation = filtered[index];
|
||||
highlights = highlights.not(annotation.highlights);
|
||||
}
|
||||
highlights.addClass(this.classes.hl.hide);
|
||||
this.filtered = this.highlights.not(this.classes.hl.hide);
|
||||
return this;
|
||||
};
|
||||
|
||||
Filter.prototype.resetHighlights = function() {
|
||||
this.highlights.removeClass(this.classes.hl.hide);
|
||||
this.filtered = this.highlights;
|
||||
return this;
|
||||
};
|
||||
|
||||
Filter.prototype._onFilterFocus = function(event) {
|
||||
var input;
|
||||
input = $(event.target);
|
||||
input.parent().addClass(this.classes.active);
|
||||
return input.next('button').show();
|
||||
};
|
||||
|
||||
Filter.prototype._onFilterBlur = function(event) {
|
||||
var input;
|
||||
if (!event.target.value) {
|
||||
input = $(event.target);
|
||||
input.parent().removeClass(this.classes.active);
|
||||
return input.next('button').hide();
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype._onFilterKeyup = function(event) {
|
||||
var filter;
|
||||
filter = $(event.target).parent().data('filter');
|
||||
if (filter) {
|
||||
return this.updateFilter(filter);
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype._findNextHighlight = function(previous) {
|
||||
var active, annotation, current, index, next, offset, operator, resetOffset;
|
||||
if (!this.highlights.length) {
|
||||
return this;
|
||||
}
|
||||
offset = previous ? 0 : -1;
|
||||
resetOffset = previous ? -1 : 0;
|
||||
operator = previous ? 'lt' : 'gt';
|
||||
active = this.highlights.not('.' + this.classes.hl.hide);
|
||||
current = active.filter('.' + this.classes.hl.active);
|
||||
if (!current.length) {
|
||||
current = active.eq(offset);
|
||||
}
|
||||
annotation = current.data('annotation');
|
||||
index = active.index(current[0]);
|
||||
next = active.filter(":" + operator + "(" + index + ")").not(annotation.highlights).eq(resetOffset);
|
||||
if (!next.length) {
|
||||
next = active.eq(resetOffset);
|
||||
}
|
||||
return this._scrollToHighlight(next.data('annotation').highlights);
|
||||
};
|
||||
|
||||
Filter.prototype._onNextClick = function(event) {
|
||||
return this._findNextHighlight();
|
||||
};
|
||||
|
||||
Filter.prototype._onPreviousClick = function(event) {
|
||||
return this._findNextHighlight(true);
|
||||
};
|
||||
|
||||
Filter.prototype._scrollToHighlight = function(highlight) {
|
||||
highlight = $(highlight);
|
||||
this.highlights.removeClass(this.classes.hl.active);
|
||||
highlight.addClass(this.classes.hl.active);
|
||||
return $('html, body').animate({
|
||||
scrollTop: highlight.offset().top - (this.element.height() + 20)
|
||||
}, 150);
|
||||
};
|
||||
|
||||
Filter.prototype._onClearClick = function(event) {
|
||||
return $(event.target).prev('input').val('').keyup().blur();
|
||||
};
|
||||
|
||||
return Filter;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Markdown = (function(_super) {
|
||||
__extends(Markdown, _super);
|
||||
|
||||
Markdown.prototype.events = {
|
||||
'annotationViewerTextField': 'updateTextField'
|
||||
};
|
||||
|
||||
function Markdown(element, options) {
|
||||
this.updateTextField = __bind(this.updateTextField, this);
|
||||
if ((typeof Showdown !== "undefined" && Showdown !== null ? Showdown.converter : void 0) != null) {
|
||||
Markdown.__super__.constructor.apply(this, arguments);
|
||||
this.converter = new Showdown.converter();
|
||||
} else {
|
||||
console.error(Annotator._t("To use the Markdown plugin, you must include Showdown into the page first."));
|
||||
}
|
||||
}
|
||||
|
||||
Markdown.prototype.updateTextField = function(field, annotation) {
|
||||
var text;
|
||||
text = Annotator.Util.escape(annotation.text || '');
|
||||
return $(field).html(this.convert(text));
|
||||
};
|
||||
|
||||
Markdown.prototype.convert = function(text) {
|
||||
return this.converter.makeHtml(text);
|
||||
};
|
||||
|
||||
return Markdown;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var _ref,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Tags = (function(_super) {
|
||||
__extends(Tags, _super);
|
||||
|
||||
function Tags() {
|
||||
this.setAnnotationTags = __bind(this.setAnnotationTags, this);
|
||||
this.updateField = __bind(this.updateField, this);
|
||||
_ref = Tags.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
Tags.prototype.options = {
|
||||
parseTags: function(string) {
|
||||
var tags;
|
||||
string = $.trim(string);
|
||||
tags = [];
|
||||
if (string) {
|
||||
tags = string.split(/\s+/);
|
||||
}
|
||||
return tags;
|
||||
},
|
||||
stringifyTags: function(array) {
|
||||
return array.join(" ");
|
||||
}
|
||||
};
|
||||
|
||||
Tags.prototype.field = null;
|
||||
|
||||
Tags.prototype.input = null;
|
||||
|
||||
Tags.prototype.pluginInit = function() {
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
this.field = this.annotator.editor.addField({
|
||||
label: Annotator._t('Add some tags here') + '\u2026',
|
||||
load: this.updateField,
|
||||
submit: this.setAnnotationTags
|
||||
});
|
||||
this.annotator.viewer.addField({
|
||||
load: this.updateViewer
|
||||
});
|
||||
if (this.annotator.plugins.Filter) {
|
||||
this.annotator.plugins.Filter.addFilter({
|
||||
label: Annotator._t('Tag'),
|
||||
property: 'tags',
|
||||
isFiltered: Annotator.Plugin.Tags.filterCallback
|
||||
});
|
||||
}
|
||||
return this.input = $(this.field).find(':input');
|
||||
};
|
||||
|
||||
Tags.prototype.parseTags = function(string) {
|
||||
return this.options.parseTags(string);
|
||||
};
|
||||
|
||||
Tags.prototype.stringifyTags = function(array) {
|
||||
return this.options.stringifyTags(array);
|
||||
};
|
||||
|
||||
Tags.prototype.updateField = function(field, annotation) {
|
||||
var value;
|
||||
value = '';
|
||||
if (annotation.tags) {
|
||||
value = this.stringifyTags(annotation.tags);
|
||||
}
|
||||
return this.input.val(value);
|
||||
};
|
||||
|
||||
Tags.prototype.setAnnotationTags = function(field, annotation) {
|
||||
return annotation.tags = this.parseTags(this.input.val());
|
||||
};
|
||||
|
||||
Tags.prototype.updateViewer = function(field, annotation) {
|
||||
field = $(field);
|
||||
if (annotation.tags && $.isArray(annotation.tags) && annotation.tags.length) {
|
||||
return field.addClass('annotator-tags').html(function() {
|
||||
var string;
|
||||
return string = $.map(annotation.tags, function(tag) {
|
||||
return '<span class="annotator-tag">' + Annotator.Util.escape(tag) + '</span>';
|
||||
}).join(' ');
|
||||
});
|
||||
} else {
|
||||
return field.remove();
|
||||
}
|
||||
};
|
||||
|
||||
return Tags;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
Annotator.Plugin.Tags.filterCallback = function(input, tags) {
|
||||
var keyword, keywords, matches, tag, _i, _j, _len, _len1;
|
||||
if (tags == null) {
|
||||
tags = [];
|
||||
}
|
||||
matches = 0;
|
||||
keywords = [];
|
||||
if (input) {
|
||||
keywords = input.split(/\s+/g);
|
||||
for (_i = 0, _len = keywords.length; _i < _len; _i++) {
|
||||
keyword = keywords[_i];
|
||||
if (tags.length) {
|
||||
for (_j = 0, _len1 = tags.length; _j < _len1; _j++) {
|
||||
tag = tags[_j];
|
||||
if (tag.indexOf(keyword) !== -1) {
|
||||
matches += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches === keywords.length;
|
||||
};
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var __hasProp = {}.hasOwnProperty,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
Annotator.prototype.setupPlugins = function(config, options) {
|
||||
var name, opts, pluginConfig, plugins, uri, win, _i, _len, _results;
|
||||
if (config == null) {
|
||||
config = {};
|
||||
}
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
win = Annotator.Util.getGlobal();
|
||||
plugins = ['Unsupported', 'Auth', 'Tags', 'Filter', 'Store', 'AnnotateItPermissions'];
|
||||
if (win.Showdown) {
|
||||
plugins.push('Markdown');
|
||||
}
|
||||
uri = win.location.href.split(/#|\?/).shift() || '';
|
||||
pluginConfig = {
|
||||
Tags: {},
|
||||
Filter: {
|
||||
filters: [
|
||||
{
|
||||
label: Annotator._t('User'),
|
||||
property: 'user'
|
||||
}, {
|
||||
label: Annotator._t('Tags'),
|
||||
property: 'tags'
|
||||
}
|
||||
]
|
||||
},
|
||||
Auth: {
|
||||
tokenUrl: config.tokenUrl || 'http://annotateit.org/api/token'
|
||||
},
|
||||
Store: {
|
||||
prefix: config.storeUrl || 'http://annotateit.org/api',
|
||||
annotationData: {
|
||||
uri: uri
|
||||
},
|
||||
loadFromSearch: {
|
||||
uri: uri
|
||||
}
|
||||
}
|
||||
};
|
||||
for (name in options) {
|
||||
if (!__hasProp.call(options, name)) continue;
|
||||
opts = options[name];
|
||||
if (__indexOf.call(plugins, name) < 0) {
|
||||
plugins.push(name);
|
||||
}
|
||||
}
|
||||
$.extend(true, pluginConfig, options);
|
||||
_results = [];
|
||||
for (_i = 0, _len = plugins.length; _i < _len; _i++) {
|
||||
name = plugins[_i];
|
||||
if (!(name in pluginConfig) || pluginConfig[name]) {
|
||||
_results.push(this.addPlugin(name, pluginConfig[name]));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
/*
|
||||
//
|
||||
*/
|
||||
538
common/static/js/vendor/ova/catch/css/main.css
vendored
@@ -1,538 +0,0 @@
|
||||
#mainCatch body,
|
||||
#mainCatch div,
|
||||
#mainCatch p,
|
||||
#mainCatch canvas,
|
||||
#mainCatch h1,
|
||||
#mainCatch h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#mainCatch h1{
|
||||
font-size: 1.6em;
|
||||
}
|
||||
|
||||
|
||||
#mainCatch body {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
#mainCatch div {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#mainCatch header {
|
||||
margin: 30px auto;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
#mainCatch #main {
|
||||
min-width: 640px;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
|
||||
/* GRID FORMATTING */
|
||||
#mainCatch .field {
|
||||
padding: 0 10px;
|
||||
float: left;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
/* ANNOTATION LIST */
|
||||
#mainCatch.annotationListContainer {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#mainCatch .annotationList {
|
||||
width: 100%;
|
||||
font-size:0.8em;
|
||||
border: 2px solid #dddddd;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#mainCatch .annotationList .ui-tabs-nav{
|
||||
background: transparent;
|
||||
border-width: 0px 0px 1px 0px;
|
||||
-moz-border-radius: 0px;
|
||||
-webkit-border-radius: 0px;
|
||||
border-radius: 0px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#mainCatch .annotationList li {
|
||||
list-style: none;
|
||||
position: relative;
|
||||
top: 0;
|
||||
margin: 1px .2em 0 0;
|
||||
border-bottom-width: 0;
|
||||
white-space: nowrap;
|
||||
float: left;
|
||||
padding: .5em 1em;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#mainCatch .annotationList .ui-state-default{
|
||||
border: 1px solid #d3d3d3;
|
||||
background: #fff 50% 50% repeat-x;
|
||||
font-weight: normal;
|
||||
color: #555555;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#mainCatch .annotationList .ui-state-default:hover{
|
||||
border: 1px solid #999999;
|
||||
background: #fff 50% 50% repeat-x;
|
||||
font-weight: normal;
|
||||
color: #212121;
|
||||
}
|
||||
|
||||
#mainCatch .annotationList .ui-state-default.active{
|
||||
border: 1px solid #aaaaaa;
|
||||
background: #dadada 50% 50% repeat-x;
|
||||
font-weight: normal;
|
||||
color: #212121;
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
#mainCatch .annotationList .header {
|
||||
background-color:whitesmoke;
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid #dddddd;
|
||||
clear:left;
|
||||
border-top:2px solid #dadada;
|
||||
}
|
||||
|
||||
|
||||
/* ANNOTATION ROW */
|
||||
#mainCatch .annotationRow {
|
||||
width: 100%;
|
||||
padding-top:12px;
|
||||
height: 30px;
|
||||
}
|
||||
#mainCatch .annotationRow.item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mainCatch .expandableIcon img, .closeDetailIcon img {
|
||||
max-width: none !important;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#mainCatch .expandableIcon .visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#mainCatch .expandableIcon .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mainCatch .annotationItem.odd .annotationRow {
|
||||
/* background-color: #eaffea; */
|
||||
}
|
||||
|
||||
#mainCatch .annotationItem.even .annotationRow {
|
||||
/* background-color: #f4fff4; */
|
||||
}
|
||||
|
||||
#mainCatch .annotationRow .expandableIcon {
|
||||
width: 4%;
|
||||
}
|
||||
|
||||
#mainCatch .annotationRow .annotatedBy {
|
||||
width: 12%;
|
||||
}
|
||||
|
||||
#mainCatch .annotationRow .body {
|
||||
width: 32%;
|
||||
}
|
||||
|
||||
#mainCatch .annotationRow .start {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
#mainCatch .annotationRow .end {
|
||||
width: 8%;
|
||||
}
|
||||
|
||||
#mainCatch .annotationRow .annotatedAt {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#mainCatch .annotationRow .totalreplies {
|
||||
width: 9%;
|
||||
}
|
||||
|
||||
#mainCatch .annotationItem.open .annotationRow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ANNOTATION DETAIL */
|
||||
#mainCatch .annotationItem.closed .annotationDetail {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mainCatch .annotationDetail {
|
||||
border-top:1px solid #cccccc;
|
||||
border-bottom:1px solid #cccccc;
|
||||
padding-left:30px;
|
||||
padding-bottom:15px;
|
||||
}
|
||||
|
||||
#mainCatch .annotationDetail .detailHeader {
|
||||
font-style: italic;
|
||||
margin-top:10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mainCatch .annotationDetail .quote {
|
||||
font-style:italic;
|
||||
color: #666666;
|
||||
background-color: #f7f579;
|
||||
padding: 7px 10px 7px 10px;
|
||||
margin: 10px 20px 5px 0px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mainCatch .annotationDetail .quote .quoteText{
|
||||
padding: 7px;
|
||||
display: inline;
|
||||
}
|
||||
#mainCatch .annotationDetail .quote .quoteItem{
|
||||
font-size: 30px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#mainCatch .annotationDetail .quote p, #mainCatch .annotationDetail .body p {
|
||||
padding:5px 0;
|
||||
}
|
||||
|
||||
|
||||
/* PLAY MEDIA BUTTON STYLING EXTERNALLY GENERATED */
|
||||
|
||||
#mainCatch .playMediaButton {
|
||||
width:18em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#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;
|
||||
border-left: 2px solid #b3ad69;
|
||||
background: #f7f579;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#f7e734), to(#f7f579));
|
||||
background: -webkit-linear-gradient(top, #f7e734, #f7f579);
|
||||
background: -moz-linear-gradient(top, #f7e734, #f7f579);
|
||||
background: -ms-linear-gradient(top, #f7e734, #f7f579);
|
||||
background: -o-linear-gradient(top, #f7e734, #f7f579);
|
||||
padding: 10px 20px;
|
||||
-webkit-border-radius: 24px;
|
||||
-moz-border-radius: 24px;
|
||||
border-radius: 24px;
|
||||
color: #000000;
|
||||
}
|
||||
#mainCatch .playMediaButton:hover, #mainCatch .zoomToImageBounds:hover {
|
||||
border-top: 2px solid #d3bd89;
|
||||
border-bottom: 2px solid #b3ad69;
|
||||
border-right: 2px solid #b3ad69;
|
||||
border-left: 2px solid #b3ad69;
|
||||
background: #f5c105;
|
||||
color: #080708;
|
||||
}
|
||||
#mainCatch .playMediaButton:active, #mainCatch .zoomToImageBounds:active {
|
||||
border-top: 2px solid #d3bd89;
|
||||
border-bottom: 2px solid #b3ad69;
|
||||
border-right: 2px solid #b3ad69;
|
||||
border-left: 2px solid #b3ad69;
|
||||
background: #eb7f0c;
|
||||
}
|
||||
|
||||
|
||||
/* TAGS */
|
||||
#mainCatch .tags {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* TAG BUTTON */
|
||||
#mainCatch .tag {
|
||||
max-width:200px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#mainCatch .tag {
|
||||
border-top: 2px solid #999999;
|
||||
border-bottom: 2px solid #999999;
|
||||
border-right: 2px solid #999999;
|
||||
border-left: 2px solid #999999;
|
||||
background: #dddddd;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#dddddd));
|
||||
background: -webkit-linear-gradient(top, #eeeeee, #dddddd);
|
||||
background: -moz-linear-gradient(top, #eeeeee, #dddddd);
|
||||
background: -ms-linear-gradient(top, #eeeeee, #dddddd);
|
||||
background: -o-linear-gradient(top, #eeeeee, #dddddd);
|
||||
padding: 5px 10px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
color: #000000;
|
||||
}
|
||||
#mainCatch .tag:hover {
|
||||
background: #cccccc;
|
||||
}
|
||||
#mainCatch .tag:active {
|
||||
background: #bbbbbb;
|
||||
}
|
||||
|
||||
/* VIDEO ANNOTATION DETAIL */
|
||||
#mainCatch .geolocationIcon img {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
#mainCatch .videoAnnotationDetail .body {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
|
||||
/*PublicPrivate Notes in My notes */
|
||||
#mainCatch .annotationListButtons span{
|
||||
display:none;
|
||||
}
|
||||
#mainCatch .annotationListButtons .PublicPrivate{
|
||||
cursor: pointer;
|
||||
}
|
||||
#mainCatch .annotationListButtons .PublicPrivate.separator,
|
||||
#mainCatch .annotationListButtons .PublicPrivate.myNotes{
|
||||
position:relative;
|
||||
float:left;
|
||||
}
|
||||
#mainCatch .annotationListButtons .PublicPrivate.active *{
|
||||
color:black;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* My notes buttons */
|
||||
#mainCatch .annotationListButtons .moreButtonCatch{
|
||||
-moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
-webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
|
||||
background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #ffffff), color-stop(1, #a6a3a3));
|
||||
background:-moz-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:-webkit-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:-o-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:-ms-linear-gradient(top, #ffffff 5%, #a6a3a3 100%);
|
||||
background:linear-gradient(to bottom, #ffffff 5%, #a6a3a3 100%);
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#a6a3a3',GradientType=0);
|
||||
|
||||
background-color:#ffffff;
|
||||
|
||||
-moz-border-radius:6px;
|
||||
-webkit-border-radius:6px;
|
||||
border-radius:6px;
|
||||
|
||||
border:1px solid #c2c2c2;
|
||||
|
||||
display:inline-block;
|
||||
color:#302f2f;
|
||||
font-family:arial;
|
||||
font-size:15px;
|
||||
font-weight:bold;
|
||||
padding:6px 24px;
|
||||
text-decoration:none;
|
||||
|
||||
text-shadow:0px 1px 0px #ffffff;
|
||||
margin: 0px 5px 10px 5px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#mainCatch .annotationListButtons .PublicPrivate{
|
||||
-moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
-webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
box-shadow:inset 0px 1px 0px 0px #ffffff;
|
||||
|
||||
background-color:#fff;
|
||||
|
||||
border:1px solid #c2c2c2;
|
||||
|
||||
display:inline-block;
|
||||
color:#302f2f;
|
||||
font-family:arial;
|
||||
font-size:14px;
|
||||
font-weight:bold;
|
||||
padding:6px 24px;
|
||||
text-decoration:none;
|
||||
|
||||
margin: 0px 0px 10px 0px;
|
||||
cursor:pointer;
|
||||
width:115px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#mainCatch .annotationListButtons .PublicPrivate.myNotes{
|
||||
-moz-border-top-left-radius:6px;
|
||||
-webkit-border-top-left-radius:6px;
|
||||
border-radius-top-left:6px;
|
||||
-moz-border-bottom-left-radius:6px;
|
||||
-webkit-border-bottom-left-radius:6px;
|
||||
border-radius-bottom-left:6px;
|
||||
}
|
||||
|
||||
#mainCatch .annotationListButtons .PublicPrivate.public{
|
||||
-moz-border-top-right-radius:6px;
|
||||
-webkit-border-top-right-radius:6px;
|
||||
border-radius-top-right:6px;
|
||||
-moz-border-bottom-right-radius:6px;
|
||||
-webkit-border-bottom-right-radius:6px;
|
||||
border-radius-bottom-right:6px;
|
||||
}
|
||||
|
||||
#mainCatch .annotationListButtons .PublicPrivate.active:hover,
|
||||
#mainCatch .annotationListButtons .PublicPrivate.active{
|
||||
color:#302f2f;
|
||||
background-color:#dadada;
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
#mainCatch .annotationListButtons .moreButtonCatch:hover {
|
||||
background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #a6a3a3), color-stop(1, #ffffff));
|
||||
background:-moz-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:-webkit-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:-o-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:-ms-linear-gradient(top, #a6a3a3 5%, #ffffff 100%);
|
||||
background:linear-gradient(to bottom, #a6a3a3 5%, #ffffff 100%);
|
||||
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#a6a3a3', endColorstr='#ffffff',GradientType=0);
|
||||
|
||||
background-color:#a6a3a3;
|
||||
}
|
||||
|
||||
#mainCatch .annotationListButtons .PublicPrivate:hover{
|
||||
background-color:#868383;
|
||||
}
|
||||
|
||||
#mainCatch .annotationListButtons .publicPrivate:active,
|
||||
#mainCatch .annotationListButtons .moreButtonCatch:active {
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
/* More Button */
|
||||
#mainCatch .annotationListButtons .moreButtonCatch{
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* control Panel */
|
||||
#mainCatch .controlPanel .groups_button,
|
||||
#mainCatch .controlPanel .share-container-annotator{
|
||||
position: relative;
|
||||
float:left;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#mainCatch .controlPanel .share-container-annotator{
|
||||
min-width: 0;
|
||||
padding-left: 4px;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
#mainCatch .controlReplies div{
|
||||
position: relative;
|
||||
float: left;
|
||||
text-decoration: underline;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mainCatch .searchbox input{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 50%;
|
||||
margin-left: 10px;
|
||||
display: inline;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#mainCatch .searchbox .dropdown-list{
|
||||
width: 18%;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#mainCatch .searchbox .search-icon{
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAA3NCSVQICAjb4U/gAAAApVBMVEVmZmaPj4/f399mZmbBwcF8fHykpKTX19dycnLl5eWDg4O5ubmfn5/MzMyHh4fp6em1tbVsbGx5eXmZmZnu7u7h4eGLi4uZmZl+fn7ExMTd3d1wcHDx8fHR0dHj4+NqamqBgYGFhYV0dHS7u7va2tp6enrn5+eoqKhubm6NjY2hoaGJiYnr6+vv7+/Hx8d2dna3t7fDw8PPz8+9vb2RkZGnp6f39/dv4zATAAAAN3RSTlP///////////////////////////////////////////////////////////////////////8AEFmdiwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAB50RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNS4xqx9I6wAAABZ0RVh0Q3JlYXRpb24gVGltZQAxMi8xNi8xM93x4EAAAAF1SURBVDiNjdThbsIgEADgk8jWYtdZsaZ22pqqmW7GGZPd+z/aDnDWApXyq9AvcAcHgAMbtJ/xRKapnMQBuJ2BabU4P4GlgLbVo6oPvnENmqJoavXVXP2w/KCf2ctKR5pk1JnlPrhK6dei/B/aFdQ9+uCEluPzduxEAddjD9wARJ1N2R0AhAsZTfjZHU1oyncHTikRazSnKMcOlAA/dui0DdKBFHphwz1tgw9yG858cERJ25DSThx4cVNUySwdWNH2/HZHpXd7kCoie30cvGbeDcctLfT9MEFMh52tPVCdIezvRbGOqDuy0zNlpurlkOjzriRlDNy5EKZw140u7YgXkSlyzvwQ40UNnba3b8P9co3FjdbpRcfMeiDi/Px1PCbLExUeHTVs4j740ColozwMkanVBQtDjCMrzj6IuXoSeBmGJqN29X6ITD0fDQtD8yClLAyRNe2cTyEy9dgULAzNnFoGIDJVgWIA1HIQRCaEHARvbTD8A+tpEWRTORVbAAAAAElFTkSuQmCC');
|
||||
width: 16px;
|
||||
background-size: cover;
|
||||
height: 16px;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#mainCatch .searchbox .clear-search-icon{
|
||||
font-size: 12px;
|
||||
text-decoration: underline;
|
||||
float: right;
|
||||
margin-top: 10px;
|
||||
padding-right: 3px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#mainCatch .searchbox .search-icon:hover{
|
||||
opacity:0.5;
|
||||
box-shadow: 2px 4px 5px #888888;
|
||||
}
|
||||
|
||||
#mainCatch .selectors{
|
||||
width:45%;
|
||||
position:relative;
|
||||
float:left;
|
||||
}
|
||||
|
||||
#mainCatch .searchbox{
|
||||
width:52%;
|
||||
position:relative;
|
||||
float:right;
|
||||
}
|
||||
|
||||
#mainCatch .searchbox .searchinst{
|
||||
float:left;
|
||||
position:relative;
|
||||
padding-right:5px;
|
||||
margin-top:8px;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
#mainCatch .replies .replyItem .deleteReply{
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mainCatch div.annotations-loading-gif{
|
||||
width:100%;
|
||||
text-align:center;
|
||||
}
|
||||
BIN
common/static/js/vendor/ova/catch/img/closeIcon.png
vendored
|
Before Width: | Height: | Size: 522 B |
|
Before Width: | Height: | Size: 599 B |
|
Before Width: | Height: | Size: 2.0 KiB |
BIN
common/static/js/vendor/ova/catch/img/fish.jpg
vendored
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 500 B |
|
Before Width: | Height: | Size: 504 B |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 422 B |
|
Before Width: | Height: | Size: 1.6 KiB |
BIN
common/static/js/vendor/ova/catch/img/share_icon.png
vendored
|
Before Width: | Height: | Size: 400 B |
1249
common/static/js/vendor/ova/catch/js/catch.js
vendored
@@ -1,1249 +0,0 @@
|
||||
/*
|
||||
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 : {};
|
||||
|
||||
|
||||
//
|
||||
// HTML TEMPLATES
|
||||
//
|
||||
CatchSources.HTMLTEMPLATES = function(root){
|
||||
var root = root || '';
|
||||
return {
|
||||
// Main
|
||||
annotationList:
|
||||
'<div class="annotationListButtons">'+
|
||||
'{{{ PublicPrivate }}}'+
|
||||
'</div>'+
|
||||
'<div class="annotationList">'+
|
||||
'{{{ MediaSelector }}}'+
|
||||
'<div class="header">'+
|
||||
'<div class="annotationRow">'+
|
||||
'<div class="expandableIcon field">'+
|
||||
'  <!-- TODO: better way to ensure width upon hide -->'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="annotatedBy field">'+
|
||||
gettext('User')+
|
||||
'</div>'+
|
||||
|
||||
'<div class="body field">'+
|
||||
gettext('Annotation')+
|
||||
'</div>'+
|
||||
|
||||
'{{#if videoFormat}}'+
|
||||
'<div class="start field">'+
|
||||
gettext('Start')+
|
||||
'</div>'+
|
||||
|
||||
'<div class="end field">'+
|
||||
gettext('End')+
|
||||
'</div>'+
|
||||
'{{/if}}'+
|
||||
|
||||
'<div class="totalreplies field">'+
|
||||
gettext('#Replies')+
|
||||
'</div>'+
|
||||
|
||||
'<div class="annotatedAt field">'+
|
||||
gettext('Date posted')+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'{{#each annotationItems}}'+
|
||||
'{{{ this }}}'+
|
||||
'{{/each}}'+
|
||||
'</div>'+
|
||||
'<div class="annotationListButtons">'+
|
||||
'<div class="moreButtonCatch">'+gettext('More')+'</div>'+
|
||||
'</div>',
|
||||
|
||||
// Main->PublicPrivateInstructor
|
||||
annotationPublicPrivateInstructor:
|
||||
'<div class="selectors"><div class="PublicPrivate myNotes active">'+gettext('My Notes')+'<span class="action">myNotes</span></div>'+
|
||||
'<div class="PublicPrivate instructor"> '+gettext('Instructor')+'<span class="action">instructor</span></div>'+
|
||||
'<div class="PublicPrivate public"> '+gettext('Public')+'<span class="action">public</span></div></div>'+
|
||||
'<div class="searchbox"><div class="searchinst">'+gettext('Search')+'</div><select class="dropdown-list">'+
|
||||
'<option>'+gettext('Users')+'</option>'+
|
||||
'<option>'+gettext('Tags')+'</option>'+
|
||||
'<option>'+gettext('Annotation Text')+'</option>'+
|
||||
'</select><input type="text" name="search"/><div class="search-icon" alt="Run search."></div><div class="clear-search-icon" alt="Clear search.">'+gettext('Clear')+'</div></div>',
|
||||
|
||||
// Main->PublicPrivate
|
||||
annotationPublicPrivate:
|
||||
'<div class="selectors"><div class="PublicPrivate myNotes active">'+gettext('My Notes')+'<span class="action">myNotes</span></div>'+
|
||||
'<div class="PublicPrivate public"> '+gettext('Public')+'<span class="action">public</span></div></div>'+
|
||||
'<div class="searchbox"><div class="searchinst">'+gettext('Search')+'</div><select class="dropdown-list">'+
|
||||
'<option>'+gettext('Users')+'</option>'+
|
||||
'<option>'+gettext('Tags')+'</option>'+
|
||||
'<option>'+gettext('Annotation Text')+'</option>'+
|
||||
'</select><input type="text" name="search"/><div class="search-icon" alt="Run search."></div><div class="clear-search-icon" alt="Clear search.">'+gettext('Clear')+'</div></div>',
|
||||
|
||||
// Main->MediaSelector
|
||||
annotationMediaSelector:
|
||||
'<ul class="ui-tabs-nav">'+
|
||||
'<li class="ui-state-default" media="text">'+
|
||||
gettext('Text')+
|
||||
'</li>'+
|
||||
'<li class="ui-state-default" media="video">'+
|
||||
gettext('Video')+
|
||||
'</li>'+
|
||||
'<li class="ui-state-default" media="image">'+
|
||||
gettext('Image')+
|
||||
'</li>'+
|
||||
'</ul>',
|
||||
|
||||
// Main->ContainerRow
|
||||
annotationItem:
|
||||
'<div class="annotationItem {{ evenOrOdd }} {{ openOrClosed }}" annotationId="{{ id }}">'+
|
||||
'{{{ annotationRow }}}'+
|
||||
'{{{ annotationDetail }}}'+
|
||||
'</div>',
|
||||
|
||||
// Main->ContainerRow->Reply
|
||||
annotationReply:
|
||||
'{{#if annotations}}'+
|
||||
'{{#each annotations}}'+
|
||||
'<blockquote class="replyItem" annotationId="{{this.id}}" style="font-size:90%">'+
|
||||
'<p>'+
|
||||
'On {{ this.updated }} <!--<a href="index.php?r=user/user/view&id={{{this.user.id}}}">-->{{{ this.user.name }}}<!--</a>-->{{#if this.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">{{{ this.id }}}</span>'+
|
||||
'<span class="latitude" style="display:none">{{{ this.geolocation.latitude }}}</span>'+
|
||||
'<span class="longitude" style="display:none">{{{ this.geolocation.longitude }}}</span>'+
|
||||
'</span>'+
|
||||
'<div id="myLocationMap" data-dropdown-content class="f-dropdown content">'+
|
||||
'<div class="map"></div>'+
|
||||
'</div>'+
|
||||
'{{/if}}'+
|
||||
'<div class="deleteReply">'+gettext('Delete')+'</div>'+
|
||||
'</p>'+
|
||||
'<p>'+
|
||||
'{{#if this.text}}'+
|
||||
'{{{this.text}}}'+
|
||||
'{{else}}'+
|
||||
'-'+
|
||||
'{{/if}}'+
|
||||
'</p>'+
|
||||
'</blockquote>'+
|
||||
'{{/each}}'+
|
||||
'{{/if}}',
|
||||
|
||||
// Main->ContainerRow->Row
|
||||
annotationRow:
|
||||
'<div class="annotationRow item">'+
|
||||
'<div class="expandableIcon field">'+
|
||||
'<img src="'+root+'expandableIcon.png" alt="View Details" />'+
|
||||
' '+
|
||||
'</div>'+
|
||||
|
||||
'<div class="annotatedBy field">'+
|
||||
'{{ user.name }}'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="body field">'+
|
||||
'{{#if plainText}}'+
|
||||
'{{deparagraph plainText}}'+
|
||||
'{{else}}'+
|
||||
'-'+
|
||||
'{{/if}}'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="start field">'+
|
||||
'{{ rangeTime.start }}'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="end field">'+
|
||||
'{{ rangeTime.end }}'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="totalreplies field">'+
|
||||
'{{ totalComments }}'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="annotatedAt field">'+
|
||||
'{{ updated }}'+
|
||||
'</div>'+
|
||||
'</div>',
|
||||
|
||||
// Main->ContainerRow->DetailRow
|
||||
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" />'+
|
||||
'</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.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>'+
|
||||
'{{/if}}'+
|
||||
'{{#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>'+
|
||||
|
||||
'<div class="controlReplies">'+
|
||||
'<div class="newReply" style="text-decoration:underline">'+gettext('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">'+gettext('Edit')+'</div>'+
|
||||
'{{/if}}'+
|
||||
'{{#if authToDeleteButton}}'+
|
||||
'<div class="deleteAnnotation" style="text-decoration:underline">'+gettext('Delete')+'</div>'+
|
||||
'{{/if}}'+
|
||||
'</div>'+
|
||||
|
||||
'<div class="replies"></div>'+
|
||||
|
||||
|
||||
'{{#if tags}}'+
|
||||
'<div class="tags">'+
|
||||
'<h3>'+gettext('Tags:')+'</h3>'+
|
||||
'{{#each tags}}'+
|
||||
'<div class="tag">'+
|
||||
'{{this}}'+
|
||||
'</div>'+
|
||||
'{{/each}}'+
|
||||
'</div>'+
|
||||
'{{/if}}'+
|
||||
|
||||
'<div class="controlPanel">'+
|
||||
'</div>'+
|
||||
'</div>',
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
CatchAnnotation = function (element, options) {
|
||||
// local variables
|
||||
var $ = jQuery,
|
||||
options = options || {};
|
||||
|
||||
// Options
|
||||
var defaultOptions = {
|
||||
media: 'text',
|
||||
userId: '', // this is an integer and its value is the userId to see user annotations
|
||||
externalLink: false, // This is true if you want to open the link in a new URL. However, it is false if you want to open the url in the same page
|
||||
showMediaSelector: true, // whether show the selector of Media Annotations or not
|
||||
showPublicPrivate: true, // Whether show Public or Private Annotation Selector
|
||||
pagination: 50, // Number of Annotations per load in the pagination
|
||||
flags:false // This checks to see if user is staff and has access to see flags
|
||||
};
|
||||
this.options = $.extend( true, defaultOptions, options );
|
||||
|
||||
// element
|
||||
this.element = element;
|
||||
|
||||
// clean boolean
|
||||
this.clean = false;
|
||||
|
||||
// Reset element an create a new element div
|
||||
element.html('<div id="mainCatch" class="annotationListContainer"></div>');
|
||||
this.current_tab = this.options.default_tab;
|
||||
// INIT
|
||||
var self = this;
|
||||
$( document ).ready(function() {
|
||||
self.init();
|
||||
self.refreshCatch(true);
|
||||
var moreBut = self.element.find('.annotationListButtons .moreButtonCatch');
|
||||
moreBut.hide();
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
CatchAnnotation.prototype = {
|
||||
init: function(){
|
||||
// Set variables
|
||||
// Initial Templates
|
||||
this.TEMPLATENAMES = [
|
||||
"annotationList", // Main
|
||||
"annotationPublicPrivate", // Main->PublicPrivate
|
||||
"annotationPublicPrivateInstructor", // Main->PublicPrivateInstructor
|
||||
"annotationMediaSelector", // Main->MediaSelector
|
||||
"annotationItem", // Main->ContainerRow
|
||||
"annotationReply", // Main->ContainerRow->Reply
|
||||
"annotationRow", // Main->ContainerRow->Row
|
||||
"annotationDetail", // Main->ContainerRow->DetailRow
|
||||
];
|
||||
// annotator
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = $.data(wrapper, 'annotator');
|
||||
this.annotator = annotator;
|
||||
|
||||
// Subscribe to annotator
|
||||
this._subscribeAnnotator();
|
||||
|
||||
//
|
||||
// Handlebars Register Library
|
||||
//
|
||||
Handlebars.registerHelper('deparagraph', function(txt) {
|
||||
var dpg = txt.replace("<p>", "").replace("</p>", "");
|
||||
return dpg;
|
||||
});
|
||||
|
||||
// Compile templates
|
||||
this.HTMLTEMPLATES = CatchSources.HTMLTEMPLATES(this.options.imageUrlRoot);
|
||||
this.TEMPLATES = {};
|
||||
this._compileTemplates();
|
||||
|
||||
// the default annotations are the user's personal ones instead of instructor.
|
||||
// if the default tab is instructor, we must refresh the catch to pull the ones
|
||||
// under the instructor's email. Calling changeUserId will update this.options.userId
|
||||
// and most importantly refresh not only the highlights (from Annotator)
|
||||
// but also the table below from the annotations database server (called Catch).
|
||||
if(this.options.default_tab.toLowerCase() === 'instructor') {
|
||||
this.changeUserId(this.options.instructor_email);
|
||||
}
|
||||
},
|
||||
//
|
||||
// GLOBAL UTILITIES
|
||||
//
|
||||
getTemplate: function(templateName) {
|
||||
return this.TEMPLATES[templateName]() || '';
|
||||
},
|
||||
refreshCatch: function(newInstance) {
|
||||
var mediaType = this.options.media || 'text';
|
||||
var annotationItems = [];
|
||||
var index = 0;
|
||||
var annotations = this.annotator.plugins['Store'].annotations || [];
|
||||
var el = $("#mainCatch.annotationListContainer");
|
||||
var self = this;
|
||||
var newInstance = newInstance || false;
|
||||
annotations.forEach(function(annotation) {
|
||||
var isMedia = annotation.media === self.options.media;
|
||||
var isUser = (typeof self.options.userId !== 'undefined' && self.options.userId !== '' && self.options.userId !== null)?
|
||||
self.options.userId === annotation.user.id:true;
|
||||
var isInList = newInstance?false:self._isInList(annotation);
|
||||
if (isMedia && isUser && !isInList) {
|
||||
var item = jQuery.extend(true, {}, annotation);
|
||||
self._formatCatch(item);
|
||||
|
||||
// Authorized
|
||||
var permissions = self.annotator.plugins.Permissions;
|
||||
var authorized = permissions.options.userAuthorize('delete', annotation, permissions.user);
|
||||
var updateAuthorized = permissions.options.userAuthorize('update', annotation, permissions.user);
|
||||
|
||||
item.authToDeleteButton = authorized;
|
||||
item.authToEditButton = updateAuthorized;
|
||||
item.hasReplies = (item.totalComments > 0);
|
||||
var html = self.TEMPLATES.annotationItem({
|
||||
item: item,
|
||||
id: item.id,
|
||||
evenOrOdd: index % 2 ? "odd" : "even",
|
||||
openOrClosed: "closed",
|
||||
annotationRow: self.TEMPLATES.annotationRow(item),
|
||||
annotationDetail: self.TEMPLATES.annotationDetail(item),
|
||||
});
|
||||
index++;
|
||||
annotationItems.push(html);
|
||||
}
|
||||
});
|
||||
|
||||
if (newInstance) {
|
||||
var videoFormat = (mediaType === "video") ? true : false;
|
||||
var publicPrivateTemplate = '';
|
||||
if (self.options.showPublicPrivate) {
|
||||
var templateName = this.options.instructor_email ?
|
||||
"annotationPublicPrivateInstructor" :
|
||||
"annotationPublicPrivate";
|
||||
}
|
||||
el.html(self.TEMPLATES.annotationList({
|
||||
annotationItems: annotationItems,
|
||||
videoFormat: videoFormat,
|
||||
PublicPrivate: this.getTemplate(templateName),
|
||||
MediaSelector: self.options.showMediaSelector?self.TEMPLATES.annotationMediaSelector():'',
|
||||
}));
|
||||
} else {
|
||||
var list = $("#mainCatch .annotationList");
|
||||
annotationItems.forEach(function(annotation) {
|
||||
list.append($(annotation));
|
||||
});
|
||||
}
|
||||
|
||||
// Set SelButtons to media
|
||||
var SelButtons = el.find('.annotationList li').removeClass('active'); // reset
|
||||
for (var index=0;index<SelButtons.length;index++) {
|
||||
var span = $(SelButtons[index]);
|
||||
if (span.attr("media") === this.options.media) $(SelButtons[index]).addClass('active');
|
||||
}
|
||||
// Set PublicPrivate
|
||||
var PublicPrivateButtons = el.find('.annotationListButtons .PublicPrivate').removeClass('active'); // reset
|
||||
for (var index=0;index<PublicPrivateButtons.length;index++) {
|
||||
var span = $(PublicPrivateButtons[index]).find('span');
|
||||
if (span.html().toLowerCase() === self.current_tab.toLowerCase()) {
|
||||
switch (self.current_tab.toLowerCase()){
|
||||
case 'public':
|
||||
self.options.userId = '';
|
||||
break;
|
||||
case 'instructor':
|
||||
self.options.userId = this.options.instructor_email;
|
||||
break;
|
||||
default:
|
||||
self.options.userId = this.annotator.plugins.Permissions.user.id;
|
||||
break;
|
||||
}
|
||||
$(PublicPrivateButtons[index]).addClass('active');
|
||||
}
|
||||
}
|
||||
|
||||
// reset all old events
|
||||
el.off();
|
||||
|
||||
// Bind functions
|
||||
var openAnnotationItem = this.__bind(this._openAnnotationItem, this);
|
||||
var closeAnnotationItem = this.__bind(this._closeAnnotationItem, this);
|
||||
var onGeolocationClick = this.__bind(this._onGeolocationClick, this);
|
||||
var onPlaySelectionClick = this.__bind(this._onPlaySelectionClick, this);
|
||||
var onShareControlsClick = this.__bind(this._onShareControlsClick, this);
|
||||
var onSelectionButtonClick = this.__bind(this._onSelectionButtonClick, this);
|
||||
var onPublicPrivateButtonClick = this.__bind(this._onPublicPrivateButtonClick, this);
|
||||
var onQuoteMediaButton = this.__bind(this._onQuoteMediaButton, this);
|
||||
var onControlRepliesClick = this.__bind(this._onControlRepliesClick, this);
|
||||
var onMoreButtonClick = this.__bind(this._onMoreButtonClick, this);
|
||||
var onSearchButtonClick = this.__bind(this._onSearchButtonClick, this);
|
||||
var onClearSearchButtonClick = this.__bind(this._onClearSearchButtonClick, this);
|
||||
var onDeleteReplyButtonClick = this.__bind(this._onDeleteReplyButtonClick, this);
|
||||
var onZoomToImageBoundsButtonClick = this.__bind(this._onZoomToImageBoundsButtonClick, this);
|
||||
var openLoadingGIF = this.__bind(this.openLoadingGIF, this);
|
||||
//Open Button
|
||||
el.on("click", ".annotationItem .annotationRow", openAnnotationItem);
|
||||
// Close Button
|
||||
el.on("click", ".annotationItem .detailHeader", closeAnnotationItem);
|
||||
// Geolocation button
|
||||
el.on("click", ".annotationItem .detailHeader .geolocationIcon img", onGeolocationClick);
|
||||
// controlPanel buttons
|
||||
el.on("click", ".annotationItem .annotationDetail .controlPanel", onShareControlsClick);
|
||||
// VIDEO
|
||||
if (this.options.media === 'video') {
|
||||
// PlaySelection button
|
||||
el.on("click", ".annotationItem .annotationDetail .playMediaButton", onPlaySelectionClick);
|
||||
}
|
||||
// TEXT
|
||||
if (this.options.media === 'text') {
|
||||
// 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);
|
||||
|
||||
// Selection Buttons
|
||||
el.on("click", ".annotationList li", onSelectionButtonClick);
|
||||
// PublicPrivate Buttons
|
||||
el.on("click", ".annotationListButtons .PublicPrivate", onPublicPrivateButtonClick);
|
||||
// More Button
|
||||
el.on("click", ".annotationListButtons .moreButtonCatch", onMoreButtonClick);
|
||||
|
||||
// Search Button
|
||||
el.on("click", ".searchbox .search-icon", onSearchButtonClick);
|
||||
// Search should also run when user hits ENTER
|
||||
$('input[name=search]').keyup(function(e) {
|
||||
// ENTER == 13
|
||||
if(e.which == 13) {
|
||||
onSearchButtonClick();
|
||||
}
|
||||
});
|
||||
|
||||
// Clear Search Button
|
||||
el.on("click", ".searchbox .clear-search-icon", onClearSearchButtonClick);
|
||||
|
||||
// Delete Reply Button
|
||||
el.on("click", ".replies .replyItem .deleteReply", onDeleteReplyButtonClick);
|
||||
|
||||
el.on("click", ".annotationListButtons .PublicPrivate", openLoadingGIF);
|
||||
},
|
||||
changeMedia: function(media) {
|
||||
var media = media || 'text';
|
||||
this.options.media = media;
|
||||
this._refresh();
|
||||
this.refreshCatch(true);
|
||||
this.checkTotAnnotations();
|
||||
},
|
||||
changeUserId: function(userId) {
|
||||
var userId = userId || '';
|
||||
this.options.userId = userId;
|
||||
this._refresh();
|
||||
this.refreshCatch(true);
|
||||
this.checkTotAnnotations();
|
||||
},
|
||||
|
||||
/**
|
||||
* This function makes sure that the annotations loaded are only the ones that we are
|
||||
* currently looking for. Annotator has a habit of loading the user's annotations
|
||||
* immediately without checking to see if we are doing some filtering or otherwise.
|
||||
* Since it's a vendor file, this is the workaround for that bug.
|
||||
*/
|
||||
cleanUpAnnotations: function(){
|
||||
var annotator = this.annotator;
|
||||
var store = annotator.plugins.Store;
|
||||
var annotations = store.annotations;
|
||||
var self = this;
|
||||
|
||||
// goes through all the annotations currently loaded
|
||||
$.each(annotations, function(key, value){
|
||||
// if the options.userID (i.e. the value we are searching for) is empty signifying
|
||||
// public or is equal to the person with update access, then we leave it alone,
|
||||
// otherwise we need to clean them up (i.e. disable them).
|
||||
if (self.options.userId !== '' && self.options.userId !== value.permissions.update[0]) {
|
||||
if (value.highlights !== undefined) {
|
||||
$.each(value.highlights, function(key1, value1){
|
||||
$(value1).removeClass('annotator-hl');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
loadAnnotations: function() {
|
||||
var annotator = this.annotator;
|
||||
var loadFromSearch = annotator.plugins.Store.options.loadFromSearch;
|
||||
var loadedAn = this.element.find('.annotationList .annotationItem').length;
|
||||
loadedAn = typeof loadedAn !== 'undefined' ?loadedAn:0;
|
||||
|
||||
loadFromSearch.limit = this.options.pagination;
|
||||
loadFromSearch.offset = loadedAn;
|
||||
loadFromSearch.media = this.options.media;
|
||||
loadFromSearch.userid = this.options.userId;
|
||||
|
||||
// Dani had this for some reason. we can't remember. but if something
|
||||
// breaks, uncomment next line.
|
||||
// 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);
|
||||
|
||||
// text loading annotations
|
||||
var moreBut = this.element.find('.annotationListButtons .moreButtonCatch');
|
||||
moreBut.html('Please wait, loading...');
|
||||
},
|
||||
|
||||
// check whether is necessary to have a more button or not
|
||||
checkTotAnnotations: function() {
|
||||
var annotator = this.annotator;
|
||||
var loadFromSearch = annotator.plugins.Store.options.loadFromSearch;
|
||||
var oldLimit = loadFromSearch.limit;
|
||||
var oldOffset = loadFromSearch.offset;
|
||||
var self = this;
|
||||
|
||||
loadFromSearch.limit = 0;
|
||||
loadFromSearch.offset = 0;
|
||||
loadFromSearch.media = this.options.media;
|
||||
loadFromSearch.userid = this.options.userId;
|
||||
var onSuccess = function(response) {
|
||||
var totAn = self.element.find('.annotationList .annotationItem').length;
|
||||
var maxAn = response.total;
|
||||
var moreBut = self.element.find('.annotationListButtons .moreButtonCatch');
|
||||
if (totAn<maxAn && totAn > 0)
|
||||
moreBut.show();
|
||||
else
|
||||
moreBut.hide();
|
||||
}
|
||||
|
||||
var obj = loadFromSearch;
|
||||
var action = 'search';
|
||||
|
||||
var id, options, url;
|
||||
id = obj && obj.id;
|
||||
url = annotator.plugins['Store']._urlFor(action, id);
|
||||
options = annotator.plugins['Store']._apiRequestOptions(action, obj, onSuccess);
|
||||
$.ajax(url, options);
|
||||
|
||||
// reset values
|
||||
loadFromSearch.limit = oldLimit;
|
||||
loadFromSearch.offset = oldOffset;
|
||||
|
||||
// set More button text
|
||||
var moreBut = this.element.find('.annotationListButtons .moreButtonCatch');
|
||||
moreBut.html('More');
|
||||
|
||||
},
|
||||
|
||||
//
|
||||
// LOCAL UTILITIES
|
||||
//
|
||||
_subscribeAnnotator: function() {
|
||||
var self = this;
|
||||
var annotator = this.annotator;
|
||||
// Subscribe to Annotator changes
|
||||
annotator.subscribe("annotationsLoaded", function (annotations) {
|
||||
self.cleanUpAnnotations();
|
||||
self.refreshCatch(self.clean);
|
||||
// hide or show more button
|
||||
self.checkTotAnnotations();
|
||||
});
|
||||
annotator.subscribe("annotationUpdated", function (annotation) {
|
||||
self.refreshCatch(true);
|
||||
self.checkTotAnnotations();
|
||||
});
|
||||
annotator.subscribe("annotationDeleted", function (annotation) {
|
||||
var annotations = annotator.plugins['Store'].annotations;
|
||||
var tot = typeof annotations !== 'undefined' ?annotations.length : 0;
|
||||
var attempts = 0; // max 100
|
||||
if(annotation.media === "image") {
|
||||
self.refreshCatch(true);
|
||||
self.checkTotAnnotations();
|
||||
} else {
|
||||
// This is to watch the annotations object, to see when is deleted the annotation
|
||||
var ischanged = function() {
|
||||
var new_tot = annotator.plugins['Store'].annotations.length;
|
||||
if (attempts<100)
|
||||
setTimeout(function() {
|
||||
if (new_tot !== tot) {
|
||||
self.refreshCatch(true);
|
||||
self.checkTotAnnotations();
|
||||
} else {
|
||||
attempts++;
|
||||
ischanged();
|
||||
}
|
||||
}, 100); // wait for the change in the annotations
|
||||
};
|
||||
ischanged();
|
||||
}
|
||||
});
|
||||
annotator.subscribe("annotationCreated", function (annotation) {
|
||||
var attempts = 0; // max 100
|
||||
// There is a delay between calls to the backend--especially reading after
|
||||
// writing. This function listens to when a function is created and waits
|
||||
// until the server provides it with an annotation id before doing anything
|
||||
// with it.
|
||||
var ischanged = function(){
|
||||
if (attempts<100)
|
||||
setTimeout(function() {
|
||||
if (typeof annotation.id !== 'undefined'){
|
||||
|
||||
// once it gets the annotation id, the table refreshes to show
|
||||
// the edits
|
||||
self.refreshCatch();
|
||||
if (typeof annotation.parent !== 'undefined' && annotation.parent !== '0'){
|
||||
|
||||
// if annotation made was actually a replay to an annotation
|
||||
// i.e. the only difference is that annotations that are
|
||||
// not replies have no "parent"
|
||||
var replies = $("[annotationid="+annotation.parent+"]").find(".controlReplies .hideReplies");
|
||||
|
||||
// forces "Show replies" section to show and then refreshes
|
||||
// via two clicks
|
||||
replies.show();
|
||||
replies.click();
|
||||
replies.click();
|
||||
}
|
||||
} else {
|
||||
attempts++;
|
||||
ischanged();
|
||||
}
|
||||
}, 100); // wait for annotation id
|
||||
};
|
||||
ischanged();
|
||||
});
|
||||
},
|
||||
__bind: function(fn, me) { return function(){ return fn.apply(me, arguments); }; },
|
||||
_compileTemplates: function() {
|
||||
var self = this;
|
||||
// Change the html tags to functions
|
||||
this.TEMPLATENAMES.forEach(function(templateName) {
|
||||
self.TEMPLATES[templateName] = Handlebars.compile(self.HTMLTEMPLATES[templateName]);
|
||||
});
|
||||
},
|
||||
_isVideoJS: function (an) {
|
||||
var annotator = this.annotator;
|
||||
var rt = an.rangeTime;
|
||||
var isOpenVideojs = (typeof annotator.mplayer !== 'undefined');
|
||||
var isVideo = (typeof an.media !== 'undefined' && an.media === 'video');
|
||||
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
|
||||
return (isOpenVideojs && isVideo && isNumber);
|
||||
},
|
||||
_isInList: function (an){
|
||||
var annotator = this.annotator;
|
||||
var isInList = false;
|
||||
var list = $('#mainCatch .annotationList .annotationRow.item');
|
||||
for (_i = 0, _len = list.length; _i < _len; _i++) {
|
||||
if (parseInt($(list[_i]).parent().attr('annotationid'), 10) === an.id)
|
||||
isInList = true;
|
||||
}
|
||||
return isInList;
|
||||
},
|
||||
_formatCatch: function(item) {
|
||||
var item = item || {};
|
||||
|
||||
if (this._isVideoJS(item)) {
|
||||
// format time
|
||||
item.rangeTime.start= typeof vjs !== 'undefined' ?
|
||||
vjs.formatTime(item.rangeTime.start) :
|
||||
item.rangeTime.start;
|
||||
item.rangeTime.end= typeof vjs !== 'undefined'?
|
||||
vjs.formatTime(item.rangeTime.end) :
|
||||
item.rangeTime.end;
|
||||
}
|
||||
// format date
|
||||
if (typeof item.updated !== 'undefined' && typeof createDateFromISO8601 !== 'undefined')
|
||||
item.updated = createDateFromISO8601(item.updated);
|
||||
// format geolocation
|
||||
if (typeof item.geolocation !== 'undefined' && (typeof item.geolocation.latitude === 'undefined' || item.geolocation.latitude === ''))
|
||||
delete item.geolocation;
|
||||
|
||||
/* NEW VARIABLES */
|
||||
// set plainText for Catch
|
||||
item.plainText = item.text.replace(/&(lt|gt);/g, function (strMatch, p1){
|
||||
return (p1 === "lt")? "<" : ">";
|
||||
}); // Change to < and > tags
|
||||
item.plainText = item.plainText.replace(/<\/?[^>]+(>|$)/g, "").replace(' ', ''); // 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) {
|
||||
var currTag = item.tags[index];
|
||||
if (currTag.indexOf("flagged-") !== -1) {
|
||||
item.tags.splice(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// EVENT HANDLER
|
||||
//
|
||||
_openAnnotationItem: function(evt) {
|
||||
var isClosed = $(evt.currentTarget).closest(".annotationItem").hasClass("closed");
|
||||
if (isClosed) {
|
||||
$(evt.currentTarget).closest(".annotationItem").removeClass("closed").addClass("open");
|
||||
// Add Share button
|
||||
var shareControl = $(evt.currentTarget).closest(".annotationItem").find('.annotationDetail .controlPanel:first'),
|
||||
annotator = this.annotator,
|
||||
idAnnotation = shareControl.parent().find('.idAnnotation').html(),
|
||||
uri = shareControl.parent().find('.uri').html();
|
||||
// remove the last share container
|
||||
shareControl.find('.share-container-annotator').remove();
|
||||
shareControl.append(annotator.plugins.Share.buildHTMLShareButton("", idAnnotation));
|
||||
// Set actions button
|
||||
annotator.plugins.Share.buttonsActions(shareControl[0], 1, uri);
|
||||
} else {
|
||||
$(evt.currentTarget).closest(".annotationItem").removeClass("open").addClass("closed");
|
||||
}
|
||||
},
|
||||
_closeAnnotationItem: function(evt) {
|
||||
var existEvent = typeof evt.target !== 'undefined' && typeof evt.target.localName !== 'undefined';
|
||||
if (existEvent && evt.target.parentNode.className !== 'geolocationIcon') {
|
||||
this._openAnnotationItem(evt);
|
||||
}
|
||||
},
|
||||
_onGeolocationClick: function(evt) {
|
||||
var latitude = $(evt.target).parent().find('.latitude').html();
|
||||
var longitude = $(evt.target).parent().find('.longitude').html();
|
||||
var imgSrc = '<img src="http://maps.googleapis.com/maps/api/staticmap?center=' + latitude + ',' + longitude + '&zoom=14&size=500x500&sensor=false&markers=color:green%7Clabel:G%7C' + latitude + ',' + longitude + '">';
|
||||
$(evt.target).parents('.detailHeader:first').find('#myLocationMap .map').html(imgSrc);
|
||||
},
|
||||
_onPlaySelectionClick: function(evt) {
|
||||
var id = parseInt($(evt.target).find('.idAnnotation').html(), 10);
|
||||
var uri = $(evt.target).find('.uri').html();
|
||||
var container = $(evt.target).find('.container').html();
|
||||
if (this.options.externalLink) {
|
||||
uri += (uri.indexOf('?') >= 0) ? '&ovaId=' + id : '?ovaId=' + id;
|
||||
location.href = uri;
|
||||
} else {
|
||||
var isContainer = typeof this.annotator.an !== 'undefined' && typeof this.annotator.an[container] !== 'undefined';
|
||||
var ovaInstance = isContainer ? this.annotator.an[container] : null;
|
||||
if (ovaInstance !== null) {
|
||||
var allannotations = this.annotator.plugins['Store'].annotations,
|
||||
ovaId = id,
|
||||
player = ovaInstance.player;
|
||||
|
||||
for (var item in allannotations) {
|
||||
var an = allannotations[item];
|
||||
if (typeof an.id !== 'undefined' && an.id === ovaId) { // this is the annotation
|
||||
if (this._isVideoJS(an)) { // It is a video
|
||||
if (player.id_ === an.target.container && player.tech.options_.source.src === an.target.src) {
|
||||
var anFound = an;
|
||||
|
||||
var playFunction = function(){
|
||||
// Fix problem with youtube videos in the first play. The plugin don't have this trigger
|
||||
if (player.techName === 'Youtube') {
|
||||
var startAPI = function() {
|
||||
|
||||
ovaInstance.showAnnotation(anFound);
|
||||
}
|
||||
if (ovaInstance.loaded)
|
||||
startAPI();
|
||||
else
|
||||
player.one('loadedRangeSlider', startAPI); // show Annotations once the RangeSlider is loaded
|
||||
} else {
|
||||
|
||||
ovaInstance.showAnnotation(anFound);
|
||||
}
|
||||
|
||||
$('html, body').animate({
|
||||
scrollTop: $("#" + player.id_).offset().top},
|
||||
'slow');
|
||||
};
|
||||
if (player.paused()) {
|
||||
player.play();
|
||||
player.one('playing', playFunction);
|
||||
} else {
|
||||
playFunction();
|
||||
}
|
||||
|
||||
return false; // this will stop the code to not set a new player.one.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_onZoomToImageBoundsButtonClick: function(evt){
|
||||
var zoomToBounds = $(evt.target).hasClass('zoomToImageBounds')?$(evt.target):$(evt.target).parents('.zoomToImageBounds:first');
|
||||
var osdaId = parseInt(zoomToBounds.find('.idAnnotation').html(), 10);
|
||||
var uri = zoomToBounds.find('.uri').html();
|
||||
|
||||
var allannotations = this.annotator.plugins['Store'].annotations;
|
||||
var osda = this.annotator.osda;
|
||||
|
||||
if (this.options.externalLink) {
|
||||
uri += (uri.indexOf('?') >= 0) ?'&osdaId=' + osdaId : '?osdaId=' + osdaId;
|
||||
location.href = uri;
|
||||
}
|
||||
for(var item in allannotations) {
|
||||
var an = allannotations[item];
|
||||
// Makes sure that all images are set to transparent in case one was
|
||||
// previously selected.
|
||||
if (an.highlights) {
|
||||
an.highlights[0].style.background = "rgba(0, 0, 0, 0)";
|
||||
}
|
||||
if (typeof an.id !== 'undefined' && an.id === osdaId) { // this is the annotation
|
||||
var bounds = new OpenSeadragon.Rect(an.bounds.x, an.bounds.y, an.bounds.width, an.bounds.height);
|
||||
osda.viewer.viewport.fitBounds(bounds, false);
|
||||
|
||||
$('html, body').animate({scrollTop: $("#"+an.target.container).offset().top},
|
||||
'slow');
|
||||
// signifies a selected annotation once OSD has zoomed in on the
|
||||
// appropriate area, it turns the background a bit yellow
|
||||
if (an.highlights !== undefined) {
|
||||
an.highlights[0].style.background = "rgba(255, 255, 10, 0.2)";
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_onQuoteMediaButton: function(evt) {
|
||||
var quote = $(evt.target).hasClass('quote')?$(evt.target):$(evt.target).parents('.quote:first');
|
||||
var id = parseInt(quote.find('.idAnnotation').html(), 10);
|
||||
var uri = quote.find('.uri').html();
|
||||
if (typeof id === 'undefined' || id === ''){
|
||||
this.refreshCatch();
|
||||
this.checkTotAnnotations();
|
||||
id = quote.find('.idAnnotation').html();
|
||||
// clickPlaySelection(evt);
|
||||
}
|
||||
if (this.options.externalLink) {
|
||||
uri += (uri.indexOf('?') >= 0)?'&ovaId='+id:'?ovaId='+id;
|
||||
location.href = uri;
|
||||
} else {
|
||||
var allannotations = this.annotator.plugins['Store'].annotations;
|
||||
var ovaId = id;
|
||||
for (var item in allannotations) {
|
||||
var an = allannotations[item];
|
||||
if (typeof an.id !== 'undefined' && an.id === ovaId) { // this is the annotation
|
||||
if(!this._isVideoJS(an)) {
|
||||
|
||||
var hasRanges = typeof an.ranges !== 'undefined' && typeof an.ranges[0] !== 'undefined',
|
||||
startOffset = hasRanges?an.ranges[0].startOffset:'',
|
||||
endOffset = hasRanges?an.ranges[0].endOffset:'';
|
||||
|
||||
if (typeof startOffset !== 'undefined' && typeof endOffset !== 'undefined' && typeof an.highlights) {
|
||||
|
||||
$(an.highlights).parent().find('.annotator-hl').removeClass('api');
|
||||
// change the color
|
||||
$(an.highlights).addClass('api');
|
||||
// animate to the annotation
|
||||
$('html, body').animate({
|
||||
scrollTop: $(an.highlights[0]).offset().top},
|
||||
'slow');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_refreshReplies: function(evt) {
|
||||
var item = $(evt.target).parents('.annotationItem:first');
|
||||
var anId = parseInt(item.attr('annotationId'), 10);
|
||||
|
||||
var replyElem = $(evt.target).parents('.annotationItem:first').find('.replies');
|
||||
var annotator = this.annotator;
|
||||
var loadFromSearchURI = annotator.plugins.Store.options.loadFromSearch.uri;
|
||||
var self = this;
|
||||
var action='search';
|
||||
var loadFromSearch={
|
||||
limit:-1,
|
||||
parentid:anId,
|
||||
uri:loadFromSearchURI,
|
||||
};
|
||||
var onSuccess=function(data) {
|
||||
if (data === null) data = {};
|
||||
annotations = data.rows || [];
|
||||
var _i, _len;
|
||||
for (_i = 0, _len = annotations.length; _i < _len; _i++) {
|
||||
|
||||
self._formatCatch(annotations[_i]);
|
||||
}
|
||||
replyElem.html(self.TEMPLATES.annotationReply({
|
||||
annotations: annotations
|
||||
}));
|
||||
var replyItems = $('.replies .replyItem');
|
||||
if (typeof replyItems !== 'undefined' && replyItems.length > 0) {
|
||||
annotations.forEach(function(ann) {
|
||||
replyItems.each(function(item) {
|
||||
var id = parseInt($(replyItems[item]).attr('annotationid'), 10);
|
||||
if (id === ann.id) {
|
||||
var perm = self.annotator.plugins.Permissions;
|
||||
if (!perm.options.userAuthorize('delete', ann, perm.user)) {
|
||||
$(replyItems[item]).find('.deleteReply').remove();
|
||||
} else {
|
||||
$(replyItems[item]).data('annotation', ann);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
var id, options, request, url;
|
||||
var store = this.annotator.plugins.Store;
|
||||
id = loadFromSearch && loadFromSearch.id;
|
||||
url = store._urlFor(action, id);
|
||||
options = store._apiRequestOptions(action, loadFromSearch, onSuccess);
|
||||
request = $.ajax(url, options);
|
||||
request._id = id;
|
||||
request._action = action;
|
||||
},
|
||||
_onControlRepliesClick: function(evt) {
|
||||
var action = $(evt.target)[0].className;
|
||||
|
||||
if (action === 'newReply') {
|
||||
var item = $(evt.target).parents('.annotationItem:first');
|
||||
var id = item.attr('annotationId');
|
||||
// Pre-show Adder
|
||||
this.annotator.adder.show();
|
||||
|
||||
// Get elements
|
||||
var replyElem = $(evt.target).parents('.annotationItem:first').find('.annotationDetail');
|
||||
var adder =this.annotator.adder;
|
||||
var wrapper = $('.annotator-wrapper');
|
||||
|
||||
// Calculate Editor position
|
||||
var positionLeft = videojs.findPosition($(evt.target).parent().find('.newReply')[0]);
|
||||
var positionAnnotator = videojs.findPosition(wrapper[0]);
|
||||
var positionAdder = {};
|
||||
|
||||
// the following addition to display makes sure the editor shows up
|
||||
// after opening TinyMCE/editor within the image source
|
||||
positionAdder.display = "block";
|
||||
positionAdder.left = positionLeft.left - positionAnnotator.left;
|
||||
positionAdder.top = positionLeft.top + 20 - positionAnnotator.top;
|
||||
|
||||
adder.css(positionAdder);
|
||||
|
||||
// Open a new annotator dialog
|
||||
this.annotator.onAdderClick();
|
||||
|
||||
// Set vertical editor
|
||||
$(this.annotator.editor.element).css(positionAdder);
|
||||
this.annotator.editor.resetOrientation();
|
||||
this.annotator.editor.invertY();
|
||||
|
||||
// set parent
|
||||
var parentValue = $(this.annotator.editor.element).find(".reply-item span.parent-annotation");
|
||||
parentValue.html(id);
|
||||
var self = this;
|
||||
|
||||
} else if (action === 'hideReplies') {
|
||||
var oldAction = $(evt.target).html();
|
||||
|
||||
if (oldAction === 'Show Replies'){
|
||||
$(evt.target).html('Hide Replies');
|
||||
} else {
|
||||
$(evt.target).html('Show Replies');
|
||||
var replyElem = $(evt.target).parents('.annotationItem:first').find('.replies');
|
||||
replyElem.html('');
|
||||
return false;
|
||||
}
|
||||
|
||||
// search
|
||||
this._refreshReplies(evt);
|
||||
} else if (action === 'deleteAnnotation') {
|
||||
if (confirm("Would you like to delete the annotation?")) {
|
||||
var annotator = this.annotator;
|
||||
var item = $(evt.target).parents('.annotationItem:first');
|
||||
var id = parseInt(item.attr('annotationId'), 10);
|
||||
var store = annotator.plugins.Store;
|
||||
var annotations = store.annotations;
|
||||
var permissions = annotator.plugins.Permissions;
|
||||
var annotation;
|
||||
annotations.forEach(function(ann) {
|
||||
if (ann.id === id)
|
||||
annotation = ann;
|
||||
});
|
||||
var authorized = permissions.options.userAuthorize('delete', annotation, permissions.user);
|
||||
if (authorized)
|
||||
annotator.deleteAnnotation(annotation);
|
||||
}
|
||||
} else if (action === 'editAnnotation') {
|
||||
|
||||
var annotator = this.annotator;
|
||||
var item = $(evt.target).parents('.annotationItem:first');
|
||||
var id = parseInt(item.attr('annotationId'), 10);
|
||||
var store = annotator.plugins.Store;
|
||||
var annotations = store.annotations;
|
||||
var permissions = annotator.plugins.Permissions;
|
||||
var annotation;
|
||||
annotations.forEach(function(ann) {
|
||||
if (ann.id === id)
|
||||
annotation = ann;
|
||||
});
|
||||
var authorized = permissions.options.userAuthorize('update', annotation, permissions.user);
|
||||
if (authorized){
|
||||
// Get elements
|
||||
var wrapper = $('.annotator-wrapper');
|
||||
// Calculate Editor position
|
||||
var positionLeft = videojs.findPosition($(evt.target).parent().find('.editAnnotation')[0]);
|
||||
var positionAnnotator = videojs.findPosition(wrapper[0]);
|
||||
var positionAdder = {};
|
||||
|
||||
positionAdder.left = positionLeft.left - positionAnnotator.left;
|
||||
positionAdder.top = positionLeft.top + 20 - positionAnnotator.top;
|
||||
var cleanup, offset, update;
|
||||
var _this = this.annotator;
|
||||
offset = positionAdder;
|
||||
update = function() {
|
||||
cleanup();
|
||||
return _this.updateAnnotation(annotation);
|
||||
};
|
||||
cleanup = function() {
|
||||
_this.unsubscribe('annotationEditorHidden', cleanup);
|
||||
return _this.unsubscribe('annotationEditorSubmit', update);
|
||||
};
|
||||
this.annotator.subscribe('annotationEditorHidden', cleanup);
|
||||
this.annotator.subscribe('annotationEditorSubmit', update);
|
||||
this.annotator.viewer.hide();
|
||||
this.annotator.showEditor(annotation, offset);
|
||||
}
|
||||
}
|
||||
},
|
||||
_onShareControlsClick: function(evt) {
|
||||
var action = $(evt.target)[0].className;
|
||||
if (action === 'privacy_button') {
|
||||
|
||||
} else if (action === 'groups_button') {
|
||||
alert("Coming soon...");
|
||||
} else if (action === 'reply_button') {
|
||||
var item = $(evt.target).parents('.annotationItem:first'),
|
||||
id = item.attr('annotationId');
|
||||
// New annotation
|
||||
var an = this.annotator.setupAnnotation(this.annotator.createAnnotation());
|
||||
an.text="010";
|
||||
an.parent = id;
|
||||
} else if (action === 'share_button') {
|
||||
|
||||
}
|
||||
},
|
||||
_onPublicPrivateButtonClick: function(evt) {
|
||||
var action = $(evt.target).find('span');
|
||||
var userId = '';
|
||||
|
||||
// Get userI
|
||||
switch (action.html()){
|
||||
case 'public':
|
||||
userId = '';
|
||||
break;
|
||||
case 'instructor':
|
||||
userId = this.options.instructor_email;
|
||||
break;
|
||||
default:
|
||||
userId = this.annotator.plugins.Permissions.user.id;
|
||||
break;
|
||||
}
|
||||
this.current_tab = action.html();
|
||||
|
||||
// checks to make sure that Grouping is redone when switching tags in text annotations
|
||||
if (this.options.media === 'text') {
|
||||
if (typeof this.annotator.plugins.Grouping !== 'undefined') {
|
||||
// this is to check if user is is MyNotes instead of the annotation component
|
||||
this.annotator.plugins.Grouping.useGrouping = this.current_tab === 'public' ? 0 : 1;
|
||||
}
|
||||
this.annotator.publish("changedTabsInCatch");
|
||||
}
|
||||
// Change userid and refresh
|
||||
this.changeUserId(userId);
|
||||
},
|
||||
_onSelectionButtonClick: function(evt) {
|
||||
var but = $(evt.target);
|
||||
var action = but.attr('media');
|
||||
|
||||
// Get action
|
||||
if (action.length<=0) action="text"; // By default
|
||||
|
||||
|
||||
// Change media and refresh
|
||||
this.changeMedia(action);
|
||||
},
|
||||
_onMoreButtonClick: function(evt) {
|
||||
this.clean = false;
|
||||
var moreBut = this.element.find('.annotationListButtons .moreButtonCatch');
|
||||
var isLoading = moreBut.html() === 'More'?false:true;
|
||||
if(!isLoading)
|
||||
this.loadAnnotations();
|
||||
},
|
||||
|
||||
_refresh:function(searchtype, searchInput) {
|
||||
var searchtype = searchtype || "";
|
||||
var searchInput = searchInput || "";
|
||||
this.clean = true;
|
||||
|
||||
// the following cannot run in notes for there are no highlights
|
||||
if ($("#notesHolder").length === 0) {
|
||||
this._clearAnnotator();
|
||||
}
|
||||
|
||||
var annotator = this.annotator;
|
||||
var loadFromSearch = annotator.plugins.Store.options.loadFromSearch;
|
||||
|
||||
loadFromSearch.limit = this.options.pagination;
|
||||
loadFromSearch.offset = 0;
|
||||
loadFromSearch.media = this.options.media;
|
||||
loadFromSearch.userid = this.options.userId;
|
||||
|
||||
loadFromSearch.username = "";
|
||||
loadFromSearch.tag = "";
|
||||
loadFromSearch.text = "";
|
||||
|
||||
if (searchtype === "Users") {
|
||||
loadFromSearch.username = searchInput;
|
||||
} else if(searchtype === "Tags") {
|
||||
loadFromSearch.tag = searchInput;
|
||||
} else {
|
||||
loadFromSearch.text = searchInput;
|
||||
}
|
||||
annotator.plugins['Store'].loadAnnotationsFromSearch(loadFromSearch);
|
||||
},
|
||||
|
||||
_onSearchButtonClick: function(evt) {
|
||||
var searchtype = this.element.find('.searchbox .dropdown-list').val();
|
||||
var searchInput = this.element.find('.searchbox input').val();
|
||||
this._refresh(searchtype, searchInput);
|
||||
|
||||
},
|
||||
_onClearSearchButtonClick: function(evt) {
|
||||
this._refresh('', '');
|
||||
},
|
||||
_clearAnnotator: function() {
|
||||
var annotator = this.annotator;
|
||||
var store = annotator.plugins.Store;
|
||||
var annotations = store.annotations.slice();
|
||||
|
||||
annotations.forEach(function(ann){
|
||||
var child, h, _i, _len, _ref;
|
||||
if (ann.highlights !== undefined) {
|
||||
_ref = ann.highlights;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
h = _ref[_i];
|
||||
if (!(h.parentNode !== undefined)) {
|
||||
continue;
|
||||
}
|
||||
child = h.childNodes[0];
|
||||
$(h).replaceWith(h.childNodes);
|
||||
}
|
||||
}
|
||||
store.unregisterAnnotation(ann);
|
||||
});
|
||||
},
|
||||
_onDeleteReplyButtonClick : function(evt) {
|
||||
var annotator = this.annotator;
|
||||
var item = $(evt.target).parents('.replyItem:first');
|
||||
var id = item.attr('annotationid');
|
||||
var permissions = annotator.plugins.Permissions;
|
||||
var annotation = item.data('annotation');
|
||||
var authorized = permissions.options.userAuthorize('delete', annotation, permissions.user);
|
||||
if(authorized){
|
||||
if(confirm('Would you like to delete this reply?')){
|
||||
annotator.plugins['Store']._apiRequest('destroy', annotation, function(){});
|
||||
item.remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
openLoadingGIF: function() {
|
||||
$('#mainCatch').append('<div class=\'annotations-loading-gif\'><img src="'+this.options.imageUrlRoot+'loading_bar.gif" /><br />Annotations Data Loading... Please Wait.</div>');
|
||||
},
|
||||
}
|
||||
2595
common/static/js/vendor/ova/catch/js/handlebars-1.1.2.js
vendored
@@ -1,2595 +0,0 @@
|
||||
/*!
|
||||
|
||||
handlebars v1.1.2
|
||||
|
||||
Copyright (C) 2011 by Yehuda Katz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
@license
|
||||
*/
|
||||
var Handlebars = (function() {
|
||||
// handlebars/safe-string.js
|
||||
var __module4__ = (function() {
|
||||
"use strict";
|
||||
var __exports__;
|
||||
// Build out our basic SafeString type
|
||||
function SafeString(string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
SafeString.prototype.toString = function() {
|
||||
return "" + this.string;
|
||||
};
|
||||
|
||||
__exports__ = SafeString;
|
||||
return __exports__;
|
||||
})();
|
||||
|
||||
// handlebars/utils.js
|
||||
var __module3__ = (function(__dependency1__) {
|
||||
"use strict";
|
||||
var __exports__ = {};
|
||||
var SafeString = __dependency1__;
|
||||
|
||||
var escape = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
"`": "`"
|
||||
};
|
||||
|
||||
var badChars = /[&<>"'`]/g;
|
||||
var possible = /[&<>"'`]/;
|
||||
|
||||
function escapeChar(chr) {
|
||||
return escape[chr] || "&";
|
||||
}
|
||||
|
||||
function extend(obj, value) {
|
||||
for(var key in value) {
|
||||
if(value.hasOwnProperty(key)) {
|
||||
obj[key] = value[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__exports__.extend = extend;var toString = Object.prototype.toString;
|
||||
__exports__.toString = toString;
|
||||
// Sourced from lodash
|
||||
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
|
||||
var isFunction = function(value) {
|
||||
return typeof value === 'function';
|
||||
};
|
||||
// fallback for older versions of Chrome and Safari
|
||||
if (isFunction(/x/)) {
|
||||
isFunction = function(value) {
|
||||
return typeof value === 'function' && toString.call(value) === '[object Function]';
|
||||
};
|
||||
}
|
||||
var isFunction;
|
||||
__exports__.isFunction = isFunction;
|
||||
var isArray = Array.isArray || function(value) {
|
||||
return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
|
||||
};
|
||||
__exports__.isArray = isArray;
|
||||
|
||||
function escapeExpression(string) {
|
||||
// don't escape SafeStrings, since they're already safe
|
||||
if (string instanceof SafeString) {
|
||||
return string.toString();
|
||||
} else if (!string && string !== 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Force a string conversion as this will be done by the append regardless and
|
||||
// the regex test will do this transparently behind the scenes, causing issues if
|
||||
// an object's to string has escaped characters in it.
|
||||
string = "" + string;
|
||||
|
||||
if(!possible.test(string)) { return string; }
|
||||
return string.replace(badChars, escapeChar);
|
||||
}
|
||||
|
||||
__exports__.escapeExpression = escapeExpression;function isEmpty(value) {
|
||||
if (!value && value !== 0) {
|
||||
return true;
|
||||
} else if (isArray(value) && value.length === 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
__exports__.isEmpty = isEmpty;
|
||||
return __exports__;
|
||||
})(__module4__);
|
||||
|
||||
// handlebars/exception.js
|
||||
var __module5__ = (function() {
|
||||
"use strict";
|
||||
var __exports__;
|
||||
|
||||
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
|
||||
|
||||
function Exception(/* message */) {
|
||||
var tmp = Error.prototype.constructor.apply(this, arguments);
|
||||
|
||||
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
|
||||
for (var idx = 0; idx < errorProps.length; idx++) {
|
||||
this[errorProps[idx]] = tmp[errorProps[idx]];
|
||||
}
|
||||
}
|
||||
|
||||
Exception.prototype = new Error();
|
||||
|
||||
__exports__ = Exception;
|
||||
return __exports__;
|
||||
})();
|
||||
|
||||
// handlebars/base.js
|
||||
var __module2__ = (function(__dependency1__, __dependency2__) {
|
||||
"use strict";
|
||||
var __exports__ = {};
|
||||
/*globals Exception, Utils */
|
||||
var Utils = __dependency1__;
|
||||
var Exception = __dependency2__;
|
||||
|
||||
var VERSION = "1.1.2";
|
||||
__exports__.VERSION = VERSION;var COMPILER_REVISION = 4;
|
||||
__exports__.COMPILER_REVISION = COMPILER_REVISION;
|
||||
var REVISION_CHANGES = {
|
||||
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
|
||||
2: '== 1.0.0-rc.3',
|
||||
3: '== 1.0.0-rc.4',
|
||||
4: '>= 1.0.0'
|
||||
};
|
||||
__exports__.REVISION_CHANGES = REVISION_CHANGES;
|
||||
var isArray = Utils.isArray,
|
||||
isFunction = Utils.isFunction,
|
||||
toString = Utils.toString,
|
||||
objectType = '[object Object]';
|
||||
|
||||
function HandlebarsEnvironment(helpers, partials) {
|
||||
this.helpers = helpers || {};
|
||||
this.partials = partials || {};
|
||||
|
||||
registerDefaultHelpers(this);
|
||||
}
|
||||
|
||||
__exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = {
|
||||
constructor: HandlebarsEnvironment,
|
||||
|
||||
logger: logger,
|
||||
log: log,
|
||||
|
||||
registerHelper: function(name, fn, inverse) {
|
||||
if (toString.call(name) === objectType) {
|
||||
if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); }
|
||||
Utils.extend(this.helpers, name);
|
||||
} else {
|
||||
if (inverse) { fn.not = inverse; }
|
||||
this.helpers[name] = fn;
|
||||
}
|
||||
},
|
||||
|
||||
registerPartial: function(name, str) {
|
||||
if (toString.call(name) === objectType) {
|
||||
Utils.extend(this.partials, name);
|
||||
} else {
|
||||
this.partials[name] = str;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function registerDefaultHelpers(instance) {
|
||||
instance.registerHelper('helperMissing', function(arg) {
|
||||
if(arguments.length === 2) {
|
||||
return undefined;
|
||||
} else {
|
||||
throw new Error("Missing helper: '" + arg + "'");
|
||||
}
|
||||
});
|
||||
|
||||
instance.registerHelper('blockHelperMissing', function(context, options) {
|
||||
var inverse = options.inverse || function() {}, fn = options.fn;
|
||||
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if(context === true) {
|
||||
return fn(this);
|
||||
} else if(context === false || context == null) {
|
||||
return inverse(this);
|
||||
} else if (isArray(context)) {
|
||||
if(context.length > 0) {
|
||||
return instance.helpers.each(context, options);
|
||||
} else {
|
||||
return inverse(this);
|
||||
}
|
||||
} else {
|
||||
return fn(context);
|
||||
}
|
||||
});
|
||||
|
||||
instance.registerHelper('each', function(context, options) {
|
||||
var fn = options.fn, inverse = options.inverse;
|
||||
var i = 0, ret = "", data;
|
||||
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if (options.data) {
|
||||
data = createFrame(options.data);
|
||||
}
|
||||
|
||||
if(context && typeof context === 'object') {
|
||||
if (isArray(context)) {
|
||||
for(var j = context.length; i<j; i++) {
|
||||
if (data) {
|
||||
data.index = i;
|
||||
data.first = (i === 0)
|
||||
data.last = (i === (context.length-1));
|
||||
}
|
||||
ret = ret + fn(context[i], { data: data });
|
||||
}
|
||||
} else {
|
||||
for(var key in context) {
|
||||
if(context.hasOwnProperty(key)) {
|
||||
if(data) { data.key = key; }
|
||||
ret = ret + fn(context[key], {data: data});
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(i === 0){
|
||||
ret = inverse(this);
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
|
||||
instance.registerHelper('if', function(conditional, options) {
|
||||
if (isFunction(conditional)) { conditional = conditional.call(this); }
|
||||
|
||||
// Default behavior is to render the positive path if the value is truthy and not empty.
|
||||
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
|
||||
// behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
|
||||
if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) {
|
||||
return options.inverse(this);
|
||||
} else {
|
||||
return options.fn(this);
|
||||
}
|
||||
});
|
||||
|
||||
instance.registerHelper('unless', function(conditional, options) {
|
||||
return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
|
||||
});
|
||||
|
||||
instance.registerHelper('with', function(context, options) {
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if (!Utils.isEmpty(context)) return options.fn(context);
|
||||
});
|
||||
|
||||
instance.registerHelper('log', function(context, options) {
|
||||
var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
|
||||
instance.log(level, context);
|
||||
});
|
||||
}
|
||||
|
||||
var logger = {
|
||||
methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
|
||||
|
||||
// State enum
|
||||
DEBUG: 0,
|
||||
INFO: 1,
|
||||
WARN: 2,
|
||||
ERROR: 3,
|
||||
level: 3,
|
||||
|
||||
// can be overridden in the host environment
|
||||
log: function(level, obj) {
|
||||
if (logger.level <= level) {
|
||||
var method = logger.methodMap[level];
|
||||
if (typeof console !== 'undefined' && console[method]) {
|
||||
console[method].call(console, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
__exports__.logger = logger;
|
||||
function log(level, obj) { logger.log(level, obj); }
|
||||
|
||||
__exports__.log = log;var createFrame = function(object) {
|
||||
var obj = {};
|
||||
Utils.extend(obj, object);
|
||||
return obj;
|
||||
};
|
||||
__exports__.createFrame = createFrame;
|
||||
return __exports__;
|
||||
})(__module3__, __module5__);
|
||||
|
||||
// handlebars/runtime.js
|
||||
var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {
|
||||
"use strict";
|
||||
var __exports__ = {};
|
||||
/*global Utils */
|
||||
var Utils = __dependency1__;
|
||||
var Exception = __dependency2__;
|
||||
var COMPILER_REVISION = __dependency3__.COMPILER_REVISION;
|
||||
var REVISION_CHANGES = __dependency3__.REVISION_CHANGES;
|
||||
|
||||
function checkRevision(compilerInfo) {
|
||||
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
|
||||
currentRevision = COMPILER_REVISION;
|
||||
|
||||
if (compilerRevision !== currentRevision) {
|
||||
if (compilerRevision < currentRevision) {
|
||||
var runtimeVersions = REVISION_CHANGES[currentRevision],
|
||||
compilerVersions = REVISION_CHANGES[compilerRevision];
|
||||
throw new Error("Template was precompiled with an older version of Handlebars than the current runtime. "+
|
||||
"Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
|
||||
} else {
|
||||
// Use the embedded version info since the runtime doesn't know about this revision yet
|
||||
throw new Error("Template was precompiled with a newer version of Handlebars than the current runtime. "+
|
||||
"Please update your runtime to a newer version ("+compilerInfo[1]+").");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this line and break up compilePartial
|
||||
|
||||
function template(templateSpec, env) {
|
||||
if (!env) {
|
||||
throw new Error("No environment passed to template");
|
||||
}
|
||||
|
||||
var invokePartialWrapper;
|
||||
if (env.compile) {
|
||||
invokePartialWrapper = function(partial, name, context, helpers, partials, data) {
|
||||
// TODO : Check this for all inputs and the options handling (partial flag, etc). This feels
|
||||
// like there should be a common exec path
|
||||
var result = invokePartial.apply(this, arguments);
|
||||
if (result) { return result; }
|
||||
|
||||
var options = { helpers: helpers, partials: partials, data: data };
|
||||
partials[name] = env.compile(partial, { data: data !== undefined }, env);
|
||||
return partials[name](context, options);
|
||||
};
|
||||
} else {
|
||||
invokePartialWrapper = function(partial, name /* , context, helpers, partials, data */) {
|
||||
var result = invokePartial.apply(this, arguments);
|
||||
if (result) { return result; }
|
||||
throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
|
||||
};
|
||||
}
|
||||
|
||||
// Just add water
|
||||
var container = {
|
||||
escapeExpression: Utils.escapeExpression,
|
||||
invokePartial: invokePartialWrapper,
|
||||
programs: [],
|
||||
program: function(i, fn, data) {
|
||||
var programWrapper = this.programs[i];
|
||||
if(data) {
|
||||
programWrapper = program(i, fn, data);
|
||||
} else if (!programWrapper) {
|
||||
programWrapper = this.programs[i] = program(i, fn);
|
||||
}
|
||||
return programWrapper;
|
||||
},
|
||||
merge: function(param, common) {
|
||||
var ret = param || common;
|
||||
|
||||
if (param && common && (param !== common)) {
|
||||
ret = {};
|
||||
Utils.extend(ret, common);
|
||||
Utils.extend(ret, param);
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
programWithDepth: programWithDepth,
|
||||
noop: noop,
|
||||
compilerInfo: null
|
||||
};
|
||||
|
||||
return function(context, options) {
|
||||
options = options || {};
|
||||
var namespace = options.partial ? options : env,
|
||||
helpers,
|
||||
partials;
|
||||
|
||||
if (!options.partial) {
|
||||
helpers = options.helpers;
|
||||
partials = options.partials;
|
||||
}
|
||||
var result = templateSpec.call(
|
||||
container,
|
||||
namespace, context,
|
||||
helpers,
|
||||
partials,
|
||||
options.data);
|
||||
|
||||
if (!options.partial) {
|
||||
checkRevision(container.compilerInfo);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
__exports__.template = template;function programWithDepth(i, fn, data /*, $depth */) {
|
||||
var args = Array.prototype.slice.call(arguments, 3);
|
||||
|
||||
var prog = function(context, options) {
|
||||
options = options || {};
|
||||
|
||||
return fn.apply(this, [context, options.data || data].concat(args));
|
||||
};
|
||||
prog.program = i;
|
||||
prog.depth = args.length;
|
||||
return prog;
|
||||
}
|
||||
|
||||
__exports__.programWithDepth = programWithDepth;function program(i, fn, data) {
|
||||
var prog = function(context, options) {
|
||||
options = options || {};
|
||||
|
||||
return fn(context, options.data || data);
|
||||
};
|
||||
prog.program = i;
|
||||
prog.depth = 0;
|
||||
return prog;
|
||||
}
|
||||
|
||||
__exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data) {
|
||||
var options = { partial: true, helpers: helpers, partials: partials, data: data };
|
||||
|
||||
if(partial === undefined) {
|
||||
throw new Exception("The partial " + name + " could not be found");
|
||||
} else if(partial instanceof Function) {
|
||||
return partial(context, options);
|
||||
}
|
||||
}
|
||||
|
||||
__exports__.invokePartial = invokePartial;function noop() { return ""; }
|
||||
|
||||
__exports__.noop = noop;
|
||||
return __exports__;
|
||||
})(__module3__, __module5__, __module2__);
|
||||
|
||||
// handlebars.runtime.js
|
||||
var __module1__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
|
||||
"use strict";
|
||||
var __exports__;
|
||||
var base = __dependency1__;
|
||||
|
||||
// Each of these augment the Handlebars object. No need to setup here.
|
||||
// (This is done to easily share code between commonjs and browse envs)
|
||||
var SafeString = __dependency2__;
|
||||
var Exception = __dependency3__;
|
||||
var Utils = __dependency4__;
|
||||
var runtime = __dependency5__;
|
||||
|
||||
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
|
||||
var create = function() {
|
||||
var hb = new base.HandlebarsEnvironment();
|
||||
|
||||
Utils.extend(hb, base);
|
||||
hb.SafeString = SafeString;
|
||||
hb.Exception = Exception;
|
||||
hb.Utils = Utils;
|
||||
|
||||
hb.VM = runtime;
|
||||
hb.template = function(spec) {
|
||||
return runtime.template(spec, hb);
|
||||
};
|
||||
|
||||
return hb;
|
||||
};
|
||||
|
||||
var Handlebars = create();
|
||||
Handlebars.create = create;
|
||||
|
||||
__exports__ = Handlebars;
|
||||
return __exports__;
|
||||
})(__module2__, __module4__, __module5__, __module3__, __module6__);
|
||||
|
||||
// handlebars/compiler/ast.js
|
||||
var __module7__ = (function(__dependency1__) {
|
||||
"use strict";
|
||||
var __exports__ = {};
|
||||
var Exception = __dependency1__;
|
||||
|
||||
function ProgramNode(statements, inverseStrip, inverse) {
|
||||
this.type = "program";
|
||||
this.statements = statements;
|
||||
this.strip = {};
|
||||
|
||||
if(inverse) {
|
||||
this.inverse = new ProgramNode(inverse, inverseStrip);
|
||||
this.strip.right = inverseStrip.left;
|
||||
} else if (inverseStrip) {
|
||||
this.strip.left = inverseStrip.right;
|
||||
}
|
||||
}
|
||||
|
||||
__exports__.ProgramNode = ProgramNode;function MustacheNode(rawParams, hash, open, strip) {
|
||||
this.type = "mustache";
|
||||
this.hash = hash;
|
||||
this.strip = strip;
|
||||
|
||||
var escapeFlag = open[3] || open[2];
|
||||
this.escaped = escapeFlag !== '{' && escapeFlag !== '&';
|
||||
|
||||
var id = this.id = rawParams[0];
|
||||
var params = this.params = rawParams.slice(1);
|
||||
|
||||
// a mustache is an eligible helper if:
|
||||
// * its id is simple (a single part, not `this` or `..`)
|
||||
var eligibleHelper = this.eligibleHelper = id.isSimple;
|
||||
|
||||
// a mustache is definitely a helper if:
|
||||
// * it is an eligible helper, and
|
||||
// * it has at least one parameter or hash segment
|
||||
this.isHelper = eligibleHelper && (params.length || hash);
|
||||
|
||||
// if a mustache is an eligible helper but not a definite
|
||||
// helper, it is ambiguous, and will be resolved in a later
|
||||
// pass or at runtime.
|
||||
}
|
||||
|
||||
__exports__.MustacheNode = MustacheNode;function PartialNode(partialName, context, strip) {
|
||||
this.type = "partial";
|
||||
this.partialName = partialName;
|
||||
this.context = context;
|
||||
this.strip = strip;
|
||||
}
|
||||
|
||||
__exports__.PartialNode = PartialNode;function BlockNode(mustache, program, inverse, close) {
|
||||
if(mustache.id.original !== close.path.original) {
|
||||
throw new Exception(mustache.id.original + " doesn't match " + close.path.original);
|
||||
}
|
||||
|
||||
this.type = "block";
|
||||
this.mustache = mustache;
|
||||
this.program = program;
|
||||
this.inverse = inverse;
|
||||
|
||||
this.strip = {
|
||||
left: mustache.strip.left,
|
||||
right: close.strip.right
|
||||
};
|
||||
|
||||
(program || inverse).strip.left = mustache.strip.right;
|
||||
(inverse || program).strip.right = close.strip.left;
|
||||
|
||||
if (inverse && !program) {
|
||||
this.isInverse = true;
|
||||
}
|
||||
}
|
||||
|
||||
__exports__.BlockNode = BlockNode;function ContentNode(string) {
|
||||
this.type = "content";
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
__exports__.ContentNode = ContentNode;function HashNode(pairs) {
|
||||
this.type = "hash";
|
||||
this.pairs = pairs;
|
||||
}
|
||||
|
||||
__exports__.HashNode = HashNode;function IdNode(parts) {
|
||||
this.type = "ID";
|
||||
|
||||
var original = "",
|
||||
dig = [],
|
||||
depth = 0;
|
||||
|
||||
for(var i=0,l=parts.length; i<l; i++) {
|
||||
var part = parts[i].part;
|
||||
original += (parts[i].separator || '') + part;
|
||||
|
||||
if (part === ".." || part === "." || part === "this") {
|
||||
if (dig.length > 0) { throw new Exception("Invalid path: " + original); }
|
||||
else if (part === "..") { depth++; }
|
||||
else { this.isScoped = true; }
|
||||
}
|
||||
else { dig.push(part); }
|
||||
}
|
||||
|
||||
this.original = original;
|
||||
this.parts = dig;
|
||||
this.string = dig.join('.');
|
||||
this.depth = depth;
|
||||
|
||||
// an ID is simple if it only has one part, and that part is not
|
||||
// `..` or `this`.
|
||||
this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
|
||||
|
||||
this.stringModeValue = this.string;
|
||||
}
|
||||
|
||||
__exports__.IdNode = IdNode;function PartialNameNode(name) {
|
||||
this.type = "PARTIAL_NAME";
|
||||
this.name = name.original;
|
||||
}
|
||||
|
||||
__exports__.PartialNameNode = PartialNameNode;function DataNode(id) {
|
||||
this.type = "DATA";
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
__exports__.DataNode = DataNode;function StringNode(string) {
|
||||
this.type = "STRING";
|
||||
this.original =
|
||||
this.string =
|
||||
this.stringModeValue = string;
|
||||
}
|
||||
|
||||
__exports__.StringNode = StringNode;function IntegerNode(integer) {
|
||||
this.type = "INTEGER";
|
||||
this.original =
|
||||
this.integer = integer;
|
||||
this.stringModeValue = Number(integer);
|
||||
}
|
||||
|
||||
__exports__.IntegerNode = IntegerNode;function BooleanNode(bool) {
|
||||
this.type = "BOOLEAN";
|
||||
this.bool = bool;
|
||||
this.stringModeValue = bool === "true";
|
||||
}
|
||||
|
||||
__exports__.BooleanNode = BooleanNode;function CommentNode(comment) {
|
||||
this.type = "comment";
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
__exports__.CommentNode = CommentNode;
|
||||
return __exports__;
|
||||
})(__module5__);
|
||||
|
||||
// handlebars/compiler/parser.js
|
||||
var __module9__ = (function() {
|
||||
"use strict";
|
||||
var __exports__;
|
||||
/* Jison generated parser */
|
||||
var handlebars = (function(){
|
||||
var parser = {trace: function trace() { },
|
||||
yy: {},
|
||||
symbols_: {"error":2,"root":3,"statements":4,"EOF":5,"program":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"CLOSE_UNESCAPED":24,"OPEN_PARTIAL":25,"partialName":26,"partial_option0":27,"inMustache_repetition0":28,"inMustache_option0":29,"dataName":30,"param":31,"STRING":32,"INTEGER":33,"BOOLEAN":34,"hash":35,"hash_repetition_plus0":36,"hashSegment":37,"ID":38,"EQUALS":39,"DATA":40,"pathSegments":41,"SEP":42,"$accept":0,"$end":1},
|
||||
terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"CLOSE_UNESCAPED",25:"OPEN_PARTIAL",32:"STRING",33:"INTEGER",34:"BOOLEAN",38:"ID",39:"EQUALS",40:"DATA",42:"SEP"},
|
||||
productions_: [0,[3,2],[3,1],[6,2],[6,3],[6,2],[6,1],[6,1],[6,0],[4,1],[4,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,4],[7,2],[17,3],[17,1],[31,1],[31,1],[31,1],[31,1],[31,1],[35,1],[37,3],[26,1],[26,1],[26,1],[30,2],[21,1],[41,3],[41,1],[27,0],[27,1],[28,0],[28,2],[29,0],[29,1],[36,1],[36,2]],
|
||||
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
|
||||
|
||||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 1: return new yy.ProgramNode($$[$0-1]);
|
||||
break;
|
||||
case 2: return new yy.ProgramNode([]);
|
||||
break;
|
||||
case 3:this.$ = new yy.ProgramNode([], $$[$0-1], $$[$0]);
|
||||
break;
|
||||
case 4:this.$ = new yy.ProgramNode($$[$0-2], $$[$0-1], $$[$0]);
|
||||
break;
|
||||
case 5:this.$ = new yy.ProgramNode($$[$0-1], $$[$0], []);
|
||||
break;
|
||||
case 6:this.$ = new yy.ProgramNode($$[$0]);
|
||||
break;
|
||||
case 7:this.$ = new yy.ProgramNode([]);
|
||||
break;
|
||||
case 8:this.$ = new yy.ProgramNode([]);
|
||||
break;
|
||||
case 9:this.$ = [$$[$0]];
|
||||
break;
|
||||
case 10: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
||||
break;
|
||||
case 11:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
|
||||
break;
|
||||
case 12:this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
|
||||
break;
|
||||
case 13:this.$ = $$[$0];
|
||||
break;
|
||||
case 14:this.$ = $$[$0];
|
||||
break;
|
||||
case 15:this.$ = new yy.ContentNode($$[$0]);
|
||||
break;
|
||||
case 16:this.$ = new yy.CommentNode($$[$0]);
|
||||
break;
|
||||
case 17:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
|
||||
break;
|
||||
case 18:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
|
||||
break;
|
||||
case 19:this.$ = {path: $$[$0-1], strip: stripFlags($$[$0-2], $$[$0])};
|
||||
break;
|
||||
case 20:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
|
||||
break;
|
||||
case 21:this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2], stripFlags($$[$0-2], $$[$0]));
|
||||
break;
|
||||
case 22:this.$ = new yy.PartialNode($$[$0-2], $$[$0-1], stripFlags($$[$0-3], $$[$0]));
|
||||
break;
|
||||
case 23:this.$ = stripFlags($$[$0-1], $$[$0]);
|
||||
break;
|
||||
case 24:this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
|
||||
break;
|
||||
case 25:this.$ = [[$$[$0]], null];
|
||||
break;
|
||||
case 26:this.$ = $$[$0];
|
||||
break;
|
||||
case 27:this.$ = new yy.StringNode($$[$0]);
|
||||
break;
|
||||
case 28:this.$ = new yy.IntegerNode($$[$0]);
|
||||
break;
|
||||
case 29:this.$ = new yy.BooleanNode($$[$0]);
|
||||
break;
|
||||
case 30:this.$ = $$[$0];
|
||||
break;
|
||||
case 31:this.$ = new yy.HashNode($$[$0]);
|
||||
break;
|
||||
case 32:this.$ = [$$[$0-2], $$[$0]];
|
||||
break;
|
||||
case 33:this.$ = new yy.PartialNameNode($$[$0]);
|
||||
break;
|
||||
case 34:this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0]));
|
||||
break;
|
||||
case 35:this.$ = new yy.PartialNameNode(new yy.IntegerNode($$[$0]));
|
||||
break;
|
||||
case 36:this.$ = new yy.DataNode($$[$0]);
|
||||
break;
|
||||
case 37:this.$ = new yy.IdNode($$[$0]);
|
||||
break;
|
||||
case 38: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2];
|
||||
break;
|
||||
case 39:this.$ = [{part: $$[$0]}];
|
||||
break;
|
||||
case 42:this.$ = [];
|
||||
break;
|
||||
case 43:$$[$0-1].push($$[$0]);
|
||||
break;
|
||||
case 46:this.$ = [$$[$0]];
|
||||
break;
|
||||
case 47:$$[$0-1].push($$[$0]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
table: [{3:1,4:2,5:[1,3],8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],25:[1,15]},{1:[3]},{5:[1,16],8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],25:[1,15]},{1:[2,2]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],25:[2,9]},{4:20,6:18,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{4:20,6:22,7:19,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,8],22:[1,13],23:[1,14],25:[1,15]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],25:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],25:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],25:[2,15]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],25:[2,16]},{17:23,21:24,30:25,38:[1,28],40:[1,27],41:26},{17:29,21:24,30:25,38:[1,28],40:[1,27],41:26},{17:30,21:24,30:25,38:[1,28],40:[1,27],41:26},{17:31,21:24,30:25,38:[1,28],40:[1,27],41:26},{21:33,26:32,32:[1,34],33:[1,35],38:[1,28],41:26},{1:[2,1]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],25:[2,10]},{10:36,20:[1,37]},{4:38,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,7],22:[1,13],23:[1,14],25:[1,15]},{7:39,8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,21],20:[2,6],22:[1,13],23:[1,14],25:[1,15]},{17:23,18:[1,40],21:24,30:25,38:[1,28],40:[1,27],41:26},{10:41,20:[1,37]},{18:[1,42]},{18:[2,42],24:[2,42],28:43,32:[2,42],33:[2,42],34:[2,42],38:[2,42],40:[2,42]},{18:[2,25],24:[2,25]},{18:[2,37],24:[2,37],32:[2,37],33:[2,37],34:[2,37],38:[2,37],40:[2,37],42:[1,44]},{21:45,38:[1,28],41:26},{18:[2,39],24:[2,39],32:[2,39],33:[2,39],34:[2,39],38:[2,39],40:[2,39],42:[2,39]},{18:[1,46]},{18:[1,47]},{24:[1,48]},{18:[2,40],21:50,27:49,38:[1,28],41:26},{18:[2,33],38:[2,33]},{18:[2,34],38:[2,34]},{18:[2,35],38:[2,35]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],25:[2,11]},{21:51,38:[1,28],41:26},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,3],22:[1,13],23:[1,14],25:[1,15]},{4:52,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,5],22:[1,13],23:[1,14],25:[1,15]},{14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],25:[2,23]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],25:[2,12]},{14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],25:[2,18]},{18:[2,44],21:56,24:[2,44],29:53,30:60,31:54,32:[1,57],33:[1,58],34:[1,59],35:55,36:61,37:62,38:[1,63],40:[1,27],41:26},{38:[1,64]},{18:[2,36],24:[2,36],32:[2,36],33:[2,36],34:[2,36],38:[2,36],40:[2,36]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],25:[2,17]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],25:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],25:[2,21]},{18:[1,65]},{18:[2,41]},{18:[1,66]},{8:17,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],25:[1,15]},{18:[2,24],24:[2,24]},{18:[2,43],24:[2,43],32:[2,43],33:[2,43],34:[2,43],38:[2,43],40:[2,43]},{18:[2,45],24:[2,45]},{18:[2,26],24:[2,26],32:[2,26],33:[2,26],34:[2,26],38:[2,26],40:[2,26]},{18:[2,27],24:[2,27],32:[2,27],33:[2,27],34:[2,27],38:[2,27],40:[2,27]},{18:[2,28],24:[2,28],32:[2,28],33:[2,28],34:[2,28],38:[2,28],40:[2,28]},{18:[2,29],24:[2,29],32:[2,29],33:[2,29],34:[2,29],38:[2,29],40:[2,29]},{18:[2,30],24:[2,30],32:[2,30],33:[2,30],34:[2,30],38:[2,30],40:[2,30]},{18:[2,31],24:[2,31],37:67,38:[1,68]},{18:[2,46],24:[2,46],38:[2,46]},{18:[2,39],24:[2,39],32:[2,39],33:[2,39],34:[2,39],38:[2,39],39:[1,69],40:[2,39],42:[2,39]},{18:[2,38],24:[2,38],32:[2,38],33:[2,38],34:[2,38],38:[2,38],40:[2,38],42:[2,38]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],25:[2,22]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],25:[2,19]},{18:[2,47],24:[2,47],38:[2,47]},{39:[1,69]},{21:56,30:60,31:70,32:[1,57],33:[1,58],34:[1,59],38:[1,28],40:[1,27],41:26},{18:[2,32],24:[2,32],38:[2,32]}],
|
||||
defaultActions: {3:[2,2],16:[2,1],50:[2,41]},
|
||||
parseError: function parseError(str, hash) {
|
||||
throw new Error(str);
|
||||
},
|
||||
parse: function parse(input) {
|
||||
var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
|
||||
this.lexer.setInput(input);
|
||||
this.lexer.yy = this.yy;
|
||||
this.yy.lexer = this.lexer;
|
||||
this.yy.parser = this;
|
||||
if (typeof this.lexer.yylloc == "undefined")
|
||||
this.lexer.yylloc = {};
|
||||
var yyloc = this.lexer.yylloc;
|
||||
lstack.push(yyloc);
|
||||
var ranges = this.lexer.options && this.lexer.options.ranges;
|
||||
if (typeof this.yy.parseError === "function")
|
||||
this.parseError = this.yy.parseError;
|
||||
function popStack(n) {
|
||||
stack.length = stack.length - 2 * n;
|
||||
vstack.length = vstack.length - n;
|
||||
lstack.length = lstack.length - n;
|
||||
}
|
||||
function lex() {
|
||||
var token;
|
||||
token = self.lexer.lex() || 1;
|
||||
if (typeof token !== "number") {
|
||||
token = self.symbols_[token] || token;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
|
||||
while (true) {
|
||||
state = stack[stack.length - 1];
|
||||
if (this.defaultActions[state]) {
|
||||
action = this.defaultActions[state];
|
||||
} else {
|
||||
if (symbol === null || typeof symbol == "undefined") {
|
||||
symbol = lex();
|
||||
}
|
||||
action = table[state] && table[state][symbol];
|
||||
}
|
||||
if (typeof action === "undefined" || !action.length || !action[0]) {
|
||||
var errStr = "";
|
||||
if (!recovering) {
|
||||
expected = [];
|
||||
for (p in table[state])
|
||||
if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'" + this.terminals_[p] + "'");
|
||||
}
|
||||
if (this.lexer.showPosition) {
|
||||
errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
|
||||
} else {
|
||||
errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
|
||||
}
|
||||
this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
||||
}
|
||||
}
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
|
||||
}
|
||||
switch (action[0]) {
|
||||
case 1:
|
||||
stack.push(symbol);
|
||||
vstack.push(this.lexer.yytext);
|
||||
lstack.push(this.lexer.yylloc);
|
||||
stack.push(action[1]);
|
||||
symbol = null;
|
||||
if (!preErrorSymbol) {
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
if (recovering > 0)
|
||||
recovering--;
|
||||
} else {
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
len = this.productions_[action[1]][1];
|
||||
yyval.$ = vstack[vstack.length - len];
|
||||
yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column};
|
||||
if (ranges) {
|
||||
yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
|
||||
}
|
||||
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
||||
if (typeof r !== "undefined") {
|
||||
return r;
|
||||
}
|
||||
if (len) {
|
||||
stack = stack.slice(0, -1 * len * 2);
|
||||
vstack = vstack.slice(0, -1 * len);
|
||||
lstack = lstack.slice(0, -1 * len);
|
||||
}
|
||||
stack.push(this.productions_[action[1]][0]);
|
||||
vstack.push(yyval.$);
|
||||
lstack.push(yyval._$);
|
||||
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
|
||||
stack.push(newState);
|
||||
break;
|
||||
case 3:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function stripFlags(open, close) {
|
||||
return {
|
||||
left: open[2] === '~',
|
||||
right: close[0] === '~' || close[1] === '~'
|
||||
};
|
||||
}
|
||||
|
||||
/* Jison generated lexer */
|
||||
var lexer = (function(){
|
||||
var lexer = ({EOF:1,
|
||||
parseError:function parseError(str, hash) {
|
||||
if (this.yy.parser) {
|
||||
this.yy.parser.parseError(str, hash);
|
||||
} else {
|
||||
throw new Error(str);
|
||||
}
|
||||
},
|
||||
setInput:function (input) {
|
||||
this._input = input;
|
||||
this._more = this._less = this.done = false;
|
||||
this.yylineno = this.yyleng = 0;
|
||||
this.yytext = this.matched = this.match = '';
|
||||
this.conditionStack = ['INITIAL'];
|
||||
this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
|
||||
if (this.options.ranges) this.yylloc.range = [0,0];
|
||||
this.offset = 0;
|
||||
return this;
|
||||
},
|
||||
input:function () {
|
||||
var ch = this._input[0];
|
||||
this.yytext += ch;
|
||||
this.yyleng++;
|
||||
this.offset++;
|
||||
this.match += ch;
|
||||
this.matched += ch;
|
||||
var lines = ch.match(/(?:\r\n?|\n).*/g);
|
||||
if (lines) {
|
||||
this.yylineno++;
|
||||
this.yylloc.last_line++;
|
||||
} else {
|
||||
this.yylloc.last_column++;
|
||||
}
|
||||
if (this.options.ranges) this.yylloc.range[1]++;
|
||||
|
||||
this._input = this._input.slice(1);
|
||||
return ch;
|
||||
},
|
||||
unput:function (ch) {
|
||||
var len = ch.length;
|
||||
var lines = ch.split(/(?:\r\n?|\n)/g);
|
||||
|
||||
this._input = ch + this._input;
|
||||
this.yytext = this.yytext.substr(0, this.yytext.length-len-1);
|
||||
//this.yyleng -= len;
|
||||
this.offset -= len;
|
||||
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
|
||||
this.match = this.match.substr(0, this.match.length-1);
|
||||
this.matched = this.matched.substr(0, this.matched.length-1);
|
||||
|
||||
if (lines.length-1) this.yylineno -= lines.length-1;
|
||||
var r = this.yylloc.range;
|
||||
|
||||
this.yylloc = {first_line: this.yylloc.first_line,
|
||||
last_line: this.yylineno+1,
|
||||
first_column: this.yylloc.first_column,
|
||||
last_column: lines ?
|
||||
(lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length:
|
||||
this.yylloc.first_column - len
|
||||
};
|
||||
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
more:function () {
|
||||
this._more = true;
|
||||
return this;
|
||||
},
|
||||
less:function (n) {
|
||||
this.unput(this.match.slice(n));
|
||||
},
|
||||
pastInput:function () {
|
||||
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
||||
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
||||
},
|
||||
upcomingInput:function () {
|
||||
var next = this.match;
|
||||
if (next.length < 20) {
|
||||
next += this._input.substr(0, 20-next.length);
|
||||
}
|
||||
return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
|
||||
},
|
||||
showPosition:function () {
|
||||
var pre = this.pastInput();
|
||||
var c = new Array(pre.length + 1).join("-");
|
||||
return pre + this.upcomingInput() + "\n" + c+"^";
|
||||
},
|
||||
next:function () {
|
||||
if (this.done) {
|
||||
return this.EOF;
|
||||
}
|
||||
if (!this._input) this.done = true;
|
||||
|
||||
var token,
|
||||
match,
|
||||
tempMatch,
|
||||
index,
|
||||
col,
|
||||
lines;
|
||||
if (!this._more) {
|
||||
this.yytext = '';
|
||||
this.match = '';
|
||||
}
|
||||
var rules = this._currentRules();
|
||||
for (var i=0;i < rules.length; i++) {
|
||||
tempMatch = this._input.match(this.rules[rules[i]]);
|
||||
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
||||
match = tempMatch;
|
||||
index = i;
|
||||
if (!this.options.flex) break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
lines = match[0].match(/(?:\r\n?|\n).*/g);
|
||||
if (lines) this.yylineno += lines.length;
|
||||
this.yylloc = {first_line: this.yylloc.last_line,
|
||||
last_line: this.yylineno+1,
|
||||
first_column: this.yylloc.last_column,
|
||||
last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length};
|
||||
this.yytext += match[0];
|
||||
this.match += match[0];
|
||||
this.matches = match;
|
||||
this.yyleng = this.yytext.length;
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [this.offset, this.offset += this.yyleng];
|
||||
}
|
||||
this._more = false;
|
||||
this._input = this._input.slice(match[0].length);
|
||||
this.matched += match[0];
|
||||
token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
|
||||
if (this.done && this._input) this.done = false;
|
||||
if (token) return token;
|
||||
else return;
|
||||
}
|
||||
if (this._input === "") {
|
||||
return this.EOF;
|
||||
} else {
|
||||
return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
|
||||
{text: "", token: null, line: this.yylineno});
|
||||
}
|
||||
},
|
||||
lex:function lex() {
|
||||
var r = this.next();
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
} else {
|
||||
return this.lex();
|
||||
}
|
||||
},
|
||||
begin:function begin(condition) {
|
||||
this.conditionStack.push(condition);
|
||||
},
|
||||
popState:function popState() {
|
||||
return this.conditionStack.pop();
|
||||
},
|
||||
_currentRules:function _currentRules() {
|
||||
return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
|
||||
},
|
||||
topState:function () {
|
||||
return this.conditionStack[this.conditionStack.length-2];
|
||||
},
|
||||
pushState:function begin(condition) {
|
||||
this.begin(condition);
|
||||
}});
|
||||
lexer.options = {};
|
||||
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
||||
|
||||
|
||||
function strip(start, end) {
|
||||
return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end);
|
||||
}
|
||||
|
||||
|
||||
var YYSTATE=YY_START
|
||||
switch($avoiding_name_collisions) {
|
||||
case 0:
|
||||
if(yy_.yytext.slice(-2) === "\\\\") {
|
||||
strip(0,1);
|
||||
this.begin("mu");
|
||||
} else if(yy_.yytext.slice(-1) === "\\") {
|
||||
strip(0,1);
|
||||
this.begin("emu");
|
||||
} else {
|
||||
this.begin("mu");
|
||||
}
|
||||
if(yy_.yytext) return 14;
|
||||
|
||||
break;
|
||||
case 1:return 14;
|
||||
break;
|
||||
case 2:
|
||||
if(yy_.yytext.slice(-1) !== "\\") this.popState();
|
||||
if(yy_.yytext.slice(-1) === "\\") strip(0,1);
|
||||
return 14;
|
||||
|
||||
break;
|
||||
case 3:strip(0,4); this.popState(); return 15;
|
||||
break;
|
||||
case 4:return 25;
|
||||
break;
|
||||
case 5:return 16;
|
||||
break;
|
||||
case 6:return 20;
|
||||
break;
|
||||
case 7:return 19;
|
||||
break;
|
||||
case 8:return 19;
|
||||
break;
|
||||
case 9:return 23;
|
||||
break;
|
||||
case 10:return 22;
|
||||
break;
|
||||
case 11:this.popState(); this.begin('com');
|
||||
break;
|
||||
case 12:strip(3,5); this.popState(); return 15;
|
||||
break;
|
||||
case 13:return 22;
|
||||
break;
|
||||
case 14:return 39;
|
||||
break;
|
||||
case 15:return 38;
|
||||
break;
|
||||
case 16:return 38;
|
||||
break;
|
||||
case 17:return 42;
|
||||
break;
|
||||
case 18:/*ignore whitespace*/
|
||||
break;
|
||||
case 19:this.popState(); return 24;
|
||||
break;
|
||||
case 20:this.popState(); return 18;
|
||||
break;
|
||||
case 21:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 32;
|
||||
break;
|
||||
case 22:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 32;
|
||||
break;
|
||||
case 23:return 40;
|
||||
break;
|
||||
case 24:return 34;
|
||||
break;
|
||||
case 25:return 34;
|
||||
break;
|
||||
case 26:return 33;
|
||||
break;
|
||||
case 27:return 38;
|
||||
break;
|
||||
case 28:yy_.yytext = strip(1,2); return 38;
|
||||
break;
|
||||
case 29:return 'INVALID';
|
||||
break;
|
||||
case 30:return 5;
|
||||
break;
|
||||
}
|
||||
};
|
||||
lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s])))/,/^(?:false(?=([~}\s])))/,/^(?:-?[0-9]+(?=([~}\s])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/];
|
||||
lexer.conditions = {"mu":{"rules":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,30],"inclusive":true}};
|
||||
return lexer;})()
|
||||
parser.lexer = lexer;
|
||||
function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
|
||||
return new Parser;
|
||||
})();__exports__ = handlebars;
|
||||
return __exports__;
|
||||
})();
|
||||
|
||||
// handlebars/compiler/base.js
|
||||
var __module8__ = (function(__dependency1__, __dependency2__) {
|
||||
"use strict";
|
||||
var __exports__ = {};
|
||||
var parser = __dependency1__;
|
||||
var AST = __dependency2__;
|
||||
|
||||
__exports__.parser = parser;
|
||||
|
||||
function parse(input) {
|
||||
// Just return if an already-compile AST was passed in.
|
||||
if(input.constructor === AST.ProgramNode) { return input; }
|
||||
|
||||
parser.yy = AST;
|
||||
return parser.parse(input);
|
||||
}
|
||||
|
||||
__exports__.parse = parse;
|
||||
return __exports__;
|
||||
})(__module9__, __module7__);
|
||||
|
||||
// handlebars/compiler/javascript-compiler.js
|
||||
var __module11__ = (function(__dependency1__) {
|
||||
"use strict";
|
||||
var __exports__;
|
||||
var COMPILER_REVISION = __dependency1__.COMPILER_REVISION;
|
||||
var REVISION_CHANGES = __dependency1__.REVISION_CHANGES;
|
||||
var log = __dependency1__.log;
|
||||
|
||||
function Literal(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
function JavaScriptCompiler() {}
|
||||
|
||||
JavaScriptCompiler.prototype = {
|
||||
// PUBLIC API: You can override these methods in a subclass to provide
|
||||
// alternative compiled forms for name lookup and buffering semantics
|
||||
nameLookup: function(parent, name /* , type*/) {
|
||||
var wrap,
|
||||
ret;
|
||||
if (parent.indexOf('depth') === 0) {
|
||||
wrap = true;
|
||||
}
|
||||
|
||||
if (/^[0-9]+$/.test(name)) {
|
||||
ret = parent + "[" + name + "]";
|
||||
} else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
|
||||
ret = parent + "." + name;
|
||||
}
|
||||
else {
|
||||
ret = parent + "['" + name + "']";
|
||||
}
|
||||
|
||||
if (wrap) {
|
||||
return '(' + parent + ' && ' + ret + ')';
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
},
|
||||
|
||||
appendToBuffer: function(string) {
|
||||
if (this.environment.isSimple) {
|
||||
return "return " + string + ";";
|
||||
} else {
|
||||
return {
|
||||
appendToBuffer: true,
|
||||
content: string,
|
||||
toString: function() { return "buffer += " + string + ";"; }
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
initializeBuffer: function() {
|
||||
return this.quotedString("");
|
||||
},
|
||||
|
||||
namespace: "Handlebars",
|
||||
// END PUBLIC API
|
||||
|
||||
compile: function(environment, options, context, asObject) {
|
||||
this.environment = environment;
|
||||
this.options = options || {};
|
||||
|
||||
log('debug', this.environment.disassemble() + "\n\n");
|
||||
|
||||
this.name = this.environment.name;
|
||||
this.isChild = !!context;
|
||||
this.context = context || {
|
||||
programs: [],
|
||||
environments: [],
|
||||
aliases: { }
|
||||
};
|
||||
|
||||
this.preamble();
|
||||
|
||||
this.stackSlot = 0;
|
||||
this.stackVars = [];
|
||||
this.registers = { list: [] };
|
||||
this.compileStack = [];
|
||||
this.inlineStack = [];
|
||||
|
||||
this.compileChildren(environment, options);
|
||||
|
||||
var opcodes = environment.opcodes, opcode;
|
||||
|
||||
this.i = 0;
|
||||
|
||||
for(var l=opcodes.length; this.i<l; this.i++) {
|
||||
opcode = opcodes[this.i];
|
||||
|
||||
if(opcode.opcode === 'DECLARE') {
|
||||
this[opcode.name] = opcode.value;
|
||||
} else {
|
||||
this[opcode.opcode].apply(this, opcode.args);
|
||||
}
|
||||
|
||||
// Reset the stripNext flag if it was not set by this operation.
|
||||
if (opcode.opcode !== this.stripNext) {
|
||||
this.stripNext = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Flush any trailing content that might be pending.
|
||||
this.pushSource('');
|
||||
|
||||
return this.createFunctionContext(asObject);
|
||||
},
|
||||
|
||||
preamble: function() {
|
||||
var out = [];
|
||||
|
||||
if (!this.isChild) {
|
||||
var namespace = this.namespace;
|
||||
|
||||
var copies = "helpers = this.merge(helpers, " + namespace + ".helpers);";
|
||||
if (this.environment.usePartial) { copies = copies + " partials = this.merge(partials, " + namespace + ".partials);"; }
|
||||
if (this.options.data) { copies = copies + " data = data || {};"; }
|
||||
out.push(copies);
|
||||
} else {
|
||||
out.push('');
|
||||
}
|
||||
|
||||
if (!this.environment.isSimple) {
|
||||
out.push(", buffer = " + this.initializeBuffer());
|
||||
} else {
|
||||
out.push("");
|
||||
}
|
||||
|
||||
// track the last context pushed into place to allow skipping the
|
||||
// getContext opcode when it would be a noop
|
||||
this.lastContext = 0;
|
||||
this.source = out;
|
||||
},
|
||||
|
||||
createFunctionContext: function(asObject) {
|
||||
var locals = this.stackVars.concat(this.registers.list);
|
||||
|
||||
if(locals.length > 0) {
|
||||
this.source[1] = this.source[1] + ", " + locals.join(", ");
|
||||
}
|
||||
|
||||
// Generate minimizer alias mappings
|
||||
if (!this.isChild) {
|
||||
for (var alias in this.context.aliases) {
|
||||
if (this.context.aliases.hasOwnProperty(alias)) {
|
||||
this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.source[1]) {
|
||||
this.source[1] = "var " + this.source[1].substring(2) + ";";
|
||||
}
|
||||
|
||||
// Merge children
|
||||
if (!this.isChild) {
|
||||
this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
|
||||
}
|
||||
|
||||
if (!this.environment.isSimple) {
|
||||
this.pushSource("return buffer;");
|
||||
}
|
||||
|
||||
var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
|
||||
|
||||
for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
|
||||
params.push("depth" + this.environment.depths.list[i]);
|
||||
}
|
||||
|
||||
// Perform a second pass over the output to merge content when possible
|
||||
var source = this.mergeSource();
|
||||
|
||||
if (!this.isChild) {
|
||||
var revision = COMPILER_REVISION,
|
||||
versions = REVISION_CHANGES[revision];
|
||||
source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
|
||||
}
|
||||
|
||||
if (asObject) {
|
||||
params.push(source);
|
||||
|
||||
return Function.apply(this, params);
|
||||
} else {
|
||||
var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + source + '}';
|
||||
log('debug', functionSource + "\n\n");
|
||||
return functionSource;
|
||||
}
|
||||
},
|
||||
mergeSource: function() {
|
||||
// WARN: We are not handling the case where buffer is still populated as the source should
|
||||
// not have buffer append operations as their final action.
|
||||
var source = '',
|
||||
buffer;
|
||||
for (var i = 0, len = this.source.length; i < len; i++) {
|
||||
var line = this.source[i];
|
||||
if (line.appendToBuffer) {
|
||||
if (buffer) {
|
||||
buffer = buffer + '\n + ' + line.content;
|
||||
} else {
|
||||
buffer = line.content;
|
||||
}
|
||||
} else {
|
||||
if (buffer) {
|
||||
source += 'buffer += ' + buffer + ';\n ';
|
||||
buffer = undefined;
|
||||
}
|
||||
source += line + '\n ';
|
||||
}
|
||||
}
|
||||
return source;
|
||||
},
|
||||
|
||||
// [blockValue]
|
||||
//
|
||||
// On stack, before: hash, inverse, program, value
|
||||
// On stack, after: return value of blockHelperMissing
|
||||
//
|
||||
// The purpose of this opcode is to take a block of the form
|
||||
// `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
|
||||
// replace it on the stack with the result of properly
|
||||
// invoking blockHelperMissing.
|
||||
blockValue: function() {
|
||||
this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
|
||||
|
||||
var params = ["depth0"];
|
||||
this.setupParams(0, params);
|
||||
|
||||
this.replaceStack(function(current) {
|
||||
params.splice(1, 0, current);
|
||||
return "blockHelperMissing.call(" + params.join(", ") + ")";
|
||||
});
|
||||
},
|
||||
|
||||
// [ambiguousBlockValue]
|
||||
//
|
||||
// On stack, before: hash, inverse, program, value
|
||||
// Compiler value, before: lastHelper=value of last found helper, if any
|
||||
// On stack, after, if no lastHelper: same as [blockValue]
|
||||
// On stack, after, if lastHelper: value
|
||||
ambiguousBlockValue: function() {
|
||||
this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
|
||||
|
||||
var params = ["depth0"];
|
||||
this.setupParams(0, params);
|
||||
|
||||
var current = this.topStack();
|
||||
params.splice(1, 0, current);
|
||||
|
||||
// Use the options value generated from the invocation
|
||||
params[params.length-1] = 'options';
|
||||
|
||||
this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
|
||||
},
|
||||
|
||||
// [appendContent]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: ...
|
||||
//
|
||||
// Appends the string value of `content` to the current buffer
|
||||
appendContent: function(content) {
|
||||
if (this.pendingContent) {
|
||||
content = this.pendingContent + content;
|
||||
}
|
||||
if (this.stripNext) {
|
||||
content = content.replace(/^\s+/, '');
|
||||
}
|
||||
|
||||
this.pendingContent = content;
|
||||
},
|
||||
|
||||
// [strip]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: ...
|
||||
//
|
||||
// Removes any trailing whitespace from the prior content node and flags
|
||||
// the next operation for stripping if it is a content node.
|
||||
strip: function() {
|
||||
if (this.pendingContent) {
|
||||
this.pendingContent = this.pendingContent.replace(/\s+$/, '');
|
||||
}
|
||||
this.stripNext = 'strip';
|
||||
},
|
||||
|
||||
// [append]
|
||||
//
|
||||
// On stack, before: value, ...
|
||||
// On stack, after: ...
|
||||
//
|
||||
// Coerces `value` to a String and appends it to the current buffer.
|
||||
//
|
||||
// If `value` is truthy, or 0, it is coerced into a string and appended
|
||||
// Otherwise, the empty string is appended
|
||||
append: function() {
|
||||
// Force anything that is inlined onto the stack so we don't have duplication
|
||||
// when we examine local
|
||||
this.flushInline();
|
||||
var local = this.popStack();
|
||||
this.pushSource("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
|
||||
if (this.environment.isSimple) {
|
||||
this.pushSource("else { " + this.appendToBuffer("''") + " }");
|
||||
}
|
||||
},
|
||||
|
||||
// [appendEscaped]
|
||||
//
|
||||
// On stack, before: value, ...
|
||||
// On stack, after: ...
|
||||
//
|
||||
// Escape `value` and append it to the buffer
|
||||
appendEscaped: function() {
|
||||
this.context.aliases.escapeExpression = 'this.escapeExpression';
|
||||
|
||||
this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
|
||||
},
|
||||
|
||||
// [getContext]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: ...
|
||||
// Compiler value, after: lastContext=depth
|
||||
//
|
||||
// Set the value of the `lastContext` compiler value to the depth
|
||||
getContext: function(depth) {
|
||||
if(this.lastContext !== depth) {
|
||||
this.lastContext = depth;
|
||||
}
|
||||
},
|
||||
|
||||
// [lookupOnContext]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: currentContext[name], ...
|
||||
//
|
||||
// Looks up the value of `name` on the current context and pushes
|
||||
// it onto the stack.
|
||||
lookupOnContext: function(name) {
|
||||
this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
|
||||
},
|
||||
|
||||
// [pushContext]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: currentContext, ...
|
||||
//
|
||||
// Pushes the value of the current context onto the stack.
|
||||
pushContext: function() {
|
||||
this.pushStackLiteral('depth' + this.lastContext);
|
||||
},
|
||||
|
||||
// [resolvePossibleLambda]
|
||||
//
|
||||
// On stack, before: value, ...
|
||||
// On stack, after: resolved value, ...
|
||||
//
|
||||
// If the `value` is a lambda, replace it on the stack by
|
||||
// the return value of the lambda
|
||||
resolvePossibleLambda: function() {
|
||||
this.context.aliases.functionType = '"function"';
|
||||
|
||||
this.replaceStack(function(current) {
|
||||
return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
|
||||
});
|
||||
},
|
||||
|
||||
// [lookup]
|
||||
//
|
||||
// On stack, before: value, ...
|
||||
// On stack, after: value[name], ...
|
||||
//
|
||||
// Replace the value on the stack with the result of looking
|
||||
// up `name` on `value`
|
||||
lookup: function(name) {
|
||||
this.replaceStack(function(current) {
|
||||
return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
|
||||
});
|
||||
},
|
||||
|
||||
// [lookupData]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: data, ...
|
||||
//
|
||||
// Push the data lookup operator
|
||||
lookupData: function() {
|
||||
this.push('data');
|
||||
},
|
||||
|
||||
// [pushStringParam]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: string, currentContext, ...
|
||||
//
|
||||
// This opcode is designed for use in string mode, which
|
||||
// provides the string value of a parameter along with its
|
||||
// depth rather than resolving it immediately.
|
||||
pushStringParam: function(string, type) {
|
||||
this.pushStackLiteral('depth' + this.lastContext);
|
||||
|
||||
this.pushString(type);
|
||||
|
||||
if (typeof string === 'string') {
|
||||
this.pushString(string);
|
||||
} else {
|
||||
this.pushStackLiteral(string);
|
||||
}
|
||||
},
|
||||
|
||||
emptyHash: function() {
|
||||
this.pushStackLiteral('{}');
|
||||
|
||||
if (this.options.stringParams) {
|
||||
this.register('hashTypes', '{}');
|
||||
this.register('hashContexts', '{}');
|
||||
}
|
||||
},
|
||||
pushHash: function() {
|
||||
this.hash = {values: [], types: [], contexts: []};
|
||||
},
|
||||
popHash: function() {
|
||||
var hash = this.hash;
|
||||
this.hash = undefined;
|
||||
|
||||
if (this.options.stringParams) {
|
||||
this.register('hashContexts', '{' + hash.contexts.join(',') + '}');
|
||||
this.register('hashTypes', '{' + hash.types.join(',') + '}');
|
||||
}
|
||||
this.push('{\n ' + hash.values.join(',\n ') + '\n }');
|
||||
},
|
||||
|
||||
// [pushString]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: quotedString(string), ...
|
||||
//
|
||||
// Push a quoted version of `string` onto the stack
|
||||
pushString: function(string) {
|
||||
this.pushStackLiteral(this.quotedString(string));
|
||||
},
|
||||
|
||||
// [push]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: expr, ...
|
||||
//
|
||||
// Push an expression onto the stack
|
||||
push: function(expr) {
|
||||
this.inlineStack.push(expr);
|
||||
return expr;
|
||||
},
|
||||
|
||||
// [pushLiteral]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: value, ...
|
||||
//
|
||||
// Pushes a value onto the stack. This operation prevents
|
||||
// the compiler from creating a temporary variable to hold
|
||||
// it.
|
||||
pushLiteral: function(value) {
|
||||
this.pushStackLiteral(value);
|
||||
},
|
||||
|
||||
// [pushProgram]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: program(guid), ...
|
||||
//
|
||||
// Push a program expression onto the stack. This takes
|
||||
// a compile-time guid and converts it into a runtime-accessible
|
||||
// expression.
|
||||
pushProgram: function(guid) {
|
||||
if (guid != null) {
|
||||
this.pushStackLiteral(this.programExpression(guid));
|
||||
} else {
|
||||
this.pushStackLiteral(null);
|
||||
}
|
||||
},
|
||||
|
||||
// [invokeHelper]
|
||||
//
|
||||
// On stack, before: hash, inverse, program, params..., ...
|
||||
// On stack, after: result of helper invocation
|
||||
//
|
||||
// Pops off the helper's parameters, invokes the helper,
|
||||
// and pushes the helper's return value onto the stack.
|
||||
//
|
||||
// If the helper is not found, `helperMissing` is called.
|
||||
invokeHelper: function(paramSize, name) {
|
||||
this.context.aliases.helperMissing = 'helpers.helperMissing';
|
||||
|
||||
var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
|
||||
var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
|
||||
|
||||
this.push(helper.name + ' || ' + nonHelper);
|
||||
this.replaceStack(function(name) {
|
||||
return name + ' ? ' + name + '.call(' +
|
||||
helper.callParams + ") " + ": helperMissing.call(" +
|
||||
helper.helperMissingParams + ")";
|
||||
});
|
||||
},
|
||||
|
||||
// [invokeKnownHelper]
|
||||
//
|
||||
// On stack, before: hash, inverse, program, params..., ...
|
||||
// On stack, after: result of helper invocation
|
||||
//
|
||||
// This operation is used when the helper is known to exist,
|
||||
// so a `helperMissing` fallback is not required.
|
||||
invokeKnownHelper: function(paramSize, name) {
|
||||
var helper = this.setupHelper(paramSize, name);
|
||||
this.push(helper.name + ".call(" + helper.callParams + ")");
|
||||
},
|
||||
|
||||
// [invokeAmbiguous]
|
||||
//
|
||||
// On stack, before: hash, inverse, program, params..., ...
|
||||
// On stack, after: result of disambiguation
|
||||
//
|
||||
// This operation is used when an expression like `{{foo}}`
|
||||
// is provided, but we don't know at compile-time whether it
|
||||
// is a helper or a path.
|
||||
//
|
||||
// This operation emits more code than the other options,
|
||||
// and can be avoided by passing the `knownHelpers` and
|
||||
// `knownHelpersOnly` flags at compile-time.
|
||||
invokeAmbiguous: function(name, helperCall) {
|
||||
this.context.aliases.functionType = '"function"';
|
||||
|
||||
this.pushStackLiteral('{}'); // Hash value
|
||||
var helper = this.setupHelper(0, name, helperCall);
|
||||
|
||||
var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
|
||||
|
||||
var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
|
||||
var nextStack = this.nextStack();
|
||||
|
||||
this.pushSource('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
|
||||
this.pushSource('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.call(' + helper.callParams + ') : ' + nextStack + '; }');
|
||||
},
|
||||
|
||||
// [invokePartial]
|
||||
//
|
||||
// On stack, before: context, ...
|
||||
// On stack after: result of partial invocation
|
||||
//
|
||||
// This operation pops off a context, invokes a partial with that context,
|
||||
// and pushes the result of the invocation back.
|
||||
invokePartial: function(name) {
|
||||
var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
|
||||
|
||||
if (this.options.data) {
|
||||
params.push("data");
|
||||
}
|
||||
|
||||
this.context.aliases.self = "this";
|
||||
this.push("self.invokePartial(" + params.join(", ") + ")");
|
||||
},
|
||||
|
||||
// [assignToHash]
|
||||
//
|
||||
// On stack, before: value, hash, ...
|
||||
// On stack, after: hash, ...
|
||||
//
|
||||
// Pops a value and hash off the stack, assigns `hash[key] = value`
|
||||
// and pushes the hash back onto the stack.
|
||||
assignToHash: function(key) {
|
||||
var value = this.popStack(),
|
||||
context,
|
||||
type;
|
||||
|
||||
if (this.options.stringParams) {
|
||||
type = this.popStack();
|
||||
context = this.popStack();
|
||||
}
|
||||
|
||||
var hash = this.hash;
|
||||
if (context) {
|
||||
hash.contexts.push("'" + key + "': " + context);
|
||||
}
|
||||
if (type) {
|
||||
hash.types.push("'" + key + "': " + type);
|
||||
}
|
||||
hash.values.push("'" + key + "': (" + value + ")");
|
||||
},
|
||||
|
||||
// HELPERS
|
||||
|
||||
compiler: JavaScriptCompiler,
|
||||
|
||||
compileChildren: function(environment, options) {
|
||||
var children = environment.children, child, compiler;
|
||||
|
||||
for(var i=0, l=children.length; i<l; i++) {
|
||||
child = children[i];
|
||||
compiler = new this.compiler();
|
||||
|
||||
var index = this.matchExistingProgram(child);
|
||||
|
||||
if (index == null) {
|
||||
this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
|
||||
index = this.context.programs.length;
|
||||
child.index = index;
|
||||
child.name = 'program' + index;
|
||||
this.context.programs[index] = compiler.compile(child, options, this.context);
|
||||
this.context.environments[index] = child;
|
||||
} else {
|
||||
child.index = index;
|
||||
child.name = 'program' + index;
|
||||
}
|
||||
}
|
||||
},
|
||||
matchExistingProgram: function(child) {
|
||||
for (var i = 0, len = this.context.environments.length; i < len; i++) {
|
||||
var environment = this.context.environments[i];
|
||||
if (environment && environment.equals(child)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
programExpression: function(guid) {
|
||||
this.context.aliases.self = "this";
|
||||
|
||||
if(guid == null) {
|
||||
return "self.noop";
|
||||
}
|
||||
|
||||
var child = this.environment.children[guid],
|
||||
depths = child.depths.list, depth;
|
||||
|
||||
var programParams = [child.index, child.name, "data"];
|
||||
|
||||
for(var i=0, l = depths.length; i<l; i++) {
|
||||
depth = depths[i];
|
||||
|
||||
if(depth === 1) { programParams.push("depth0"); }
|
||||
else { programParams.push("depth" + (depth - 1)); }
|
||||
}
|
||||
|
||||
return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
|
||||
},
|
||||
|
||||
register: function(name, val) {
|
||||
this.useRegister(name);
|
||||
this.pushSource(name + " = " + val + ";");
|
||||
},
|
||||
|
||||
useRegister: function(name) {
|
||||
if(!this.registers[name]) {
|
||||
this.registers[name] = true;
|
||||
this.registers.list.push(name);
|
||||
}
|
||||
},
|
||||
|
||||
pushStackLiteral: function(item) {
|
||||
return this.push(new Literal(item));
|
||||
},
|
||||
|
||||
pushSource: function(source) {
|
||||
if (this.pendingContent) {
|
||||
this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent)));
|
||||
this.pendingContent = undefined;
|
||||
}
|
||||
|
||||
if (source) {
|
||||
this.source.push(source);
|
||||
}
|
||||
},
|
||||
|
||||
pushStack: function(item) {
|
||||
this.flushInline();
|
||||
|
||||
var stack = this.incrStack();
|
||||
if (item) {
|
||||
this.pushSource(stack + " = " + item + ";");
|
||||
}
|
||||
this.compileStack.push(stack);
|
||||
return stack;
|
||||
},
|
||||
|
||||
replaceStack: function(callback) {
|
||||
var prefix = '',
|
||||
inline = this.isInline(),
|
||||
stack;
|
||||
|
||||
// If we are currently inline then we want to merge the inline statement into the
|
||||
// replacement statement via ','
|
||||
if (inline) {
|
||||
var top = this.popStack(true);
|
||||
|
||||
if (top instanceof Literal) {
|
||||
// Literals do not need to be inlined
|
||||
stack = top.value;
|
||||
} else {
|
||||
// Get or create the current stack name for use by the inline
|
||||
var name = this.stackSlot ? this.topStackName() : this.incrStack();
|
||||
|
||||
prefix = '(' + this.push(name) + ' = ' + top + '),';
|
||||
stack = this.topStack();
|
||||
}
|
||||
} else {
|
||||
stack = this.topStack();
|
||||
}
|
||||
|
||||
var item = callback.call(this, stack);
|
||||
|
||||
if (inline) {
|
||||
if (this.inlineStack.length || this.compileStack.length) {
|
||||
this.popStack();
|
||||
}
|
||||
this.push('(' + prefix + item + ')');
|
||||
} else {
|
||||
// Prevent modification of the context depth variable. Through replaceStack
|
||||
if (!/^stack/.test(stack)) {
|
||||
stack = this.nextStack();
|
||||
}
|
||||
|
||||
this.pushSource(stack + " = (" + prefix + item + ");");
|
||||
}
|
||||
return stack;
|
||||
},
|
||||
|
||||
nextStack: function() {
|
||||
return this.pushStack();
|
||||
},
|
||||
|
||||
incrStack: function() {
|
||||
this.stackSlot++;
|
||||
if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
|
||||
return this.topStackName();
|
||||
},
|
||||
topStackName: function() {
|
||||
return "stack" + this.stackSlot;
|
||||
},
|
||||
flushInline: function() {
|
||||
var inlineStack = this.inlineStack;
|
||||
if (inlineStack.length) {
|
||||
this.inlineStack = [];
|
||||
for (var i = 0, len = inlineStack.length; i < len; i++) {
|
||||
var entry = inlineStack[i];
|
||||
if (entry instanceof Literal) {
|
||||
this.compileStack.push(entry);
|
||||
} else {
|
||||
this.pushStack(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
isInline: function() {
|
||||
return this.inlineStack.length;
|
||||
},
|
||||
|
||||
popStack: function(wrapped) {
|
||||
var inline = this.isInline(),
|
||||
item = (inline ? this.inlineStack : this.compileStack).pop();
|
||||
|
||||
if (!wrapped && (item instanceof Literal)) {
|
||||
return item.value;
|
||||
} else {
|
||||
if (!inline) {
|
||||
this.stackSlot--;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
},
|
||||
|
||||
topStack: function(wrapped) {
|
||||
var stack = (this.isInline() ? this.inlineStack : this.compileStack),
|
||||
item = stack[stack.length - 1];
|
||||
|
||||
if (!wrapped && (item instanceof Literal)) {
|
||||
return item.value;
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
},
|
||||
|
||||
quotedString: function(str) {
|
||||
return '"' + str
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/\n/g, '\\n')
|
||||
.replace(/\r/g, '\\r')
|
||||
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
|
||||
.replace(/\u2029/g, '\\u2029') + '"';
|
||||
},
|
||||
|
||||
setupHelper: function(paramSize, name, missingParams) {
|
||||
var params = [];
|
||||
this.setupParams(paramSize, params, missingParams);
|
||||
var foundHelper = this.nameLookup('helpers', name, 'helper');
|
||||
|
||||
return {
|
||||
params: params,
|
||||
name: foundHelper,
|
||||
callParams: ["depth0"].concat(params).join(", "),
|
||||
helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
|
||||
};
|
||||
},
|
||||
|
||||
// the params and contexts arguments are passed in arrays
|
||||
// to fill in
|
||||
setupParams: function(paramSize, params, useRegister) {
|
||||
var options = [], contexts = [], types = [], param, inverse, program;
|
||||
|
||||
options.push("hash:" + this.popStack());
|
||||
|
||||
inverse = this.popStack();
|
||||
program = this.popStack();
|
||||
|
||||
// Avoid setting fn and inverse if neither are set. This allows
|
||||
// helpers to do a check for `if (options.fn)`
|
||||
if (program || inverse) {
|
||||
if (!program) {
|
||||
this.context.aliases.self = "this";
|
||||
program = "self.noop";
|
||||
}
|
||||
|
||||
if (!inverse) {
|
||||
this.context.aliases.self = "this";
|
||||
inverse = "self.noop";
|
||||
}
|
||||
|
||||
options.push("inverse:" + inverse);
|
||||
options.push("fn:" + program);
|
||||
}
|
||||
|
||||
for(var i=0; i<paramSize; i++) {
|
||||
param = this.popStack();
|
||||
params.push(param);
|
||||
|
||||
if(this.options.stringParams) {
|
||||
types.push(this.popStack());
|
||||
contexts.push(this.popStack());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.stringParams) {
|
||||
options.push("contexts:[" + contexts.join(",") + "]");
|
||||
options.push("types:[" + types.join(",") + "]");
|
||||
options.push("hashContexts:hashContexts");
|
||||
options.push("hashTypes:hashTypes");
|
||||
}
|
||||
|
||||
if(this.options.data) {
|
||||
options.push("data:data");
|
||||
}
|
||||
|
||||
options = "{" + options.join(",") + "}";
|
||||
if (useRegister) {
|
||||
this.register('options', options);
|
||||
params.push('options');
|
||||
} else {
|
||||
params.push(options);
|
||||
}
|
||||
return params.join(", ");
|
||||
}
|
||||
};
|
||||
|
||||
var reservedWords = (
|
||||
"break else new var" +
|
||||
" case finally return void" +
|
||||
" catch for switch while" +
|
||||
" continue function this with" +
|
||||
" default if throw" +
|
||||
" delete in try" +
|
||||
" do instanceof typeof" +
|
||||
" abstract enum int short" +
|
||||
" boolean export interface static" +
|
||||
" byte extends long super" +
|
||||
" char final native synchronized" +
|
||||
" class float package throws" +
|
||||
" const goto private transient" +
|
||||
" debugger implements protected volatile" +
|
||||
" double import public let yield"
|
||||
).split(" ");
|
||||
|
||||
var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
|
||||
|
||||
for(var i=0, l=reservedWords.length; i<l; i++) {
|
||||
compilerWords[reservedWords[i]] = true;
|
||||
}
|
||||
|
||||
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
|
||||
if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
__exports__ = JavaScriptCompiler;
|
||||
return __exports__;
|
||||
})(__module2__);
|
||||
|
||||
// handlebars/compiler/compiler.js
|
||||
var __module10__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) {
|
||||
"use strict";
|
||||
var __exports__ = {};
|
||||
var Exception = __dependency1__;
|
||||
var parse = __dependency2__.parse;
|
||||
var JavaScriptCompiler = __dependency3__;
|
||||
var AST = __dependency4__;
|
||||
|
||||
function Compiler() {}
|
||||
|
||||
__exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a
|
||||
// function in a context. This is necessary for mustache compatibility, which
|
||||
// requires that context functions in blocks are evaluated by blockHelperMissing,
|
||||
// and then proceed as if the resulting value was provided to blockHelperMissing.
|
||||
|
||||
Compiler.prototype = {
|
||||
compiler: Compiler,
|
||||
|
||||
disassemble: function() {
|
||||
var opcodes = this.opcodes, opcode, out = [], params, param;
|
||||
|
||||
for (var i=0, l=opcodes.length; i<l; i++) {
|
||||
opcode = opcodes[i];
|
||||
|
||||
if (opcode.opcode === 'DECLARE') {
|
||||
out.push("DECLARE " + opcode.name + "=" + opcode.value);
|
||||
} else {
|
||||
params = [];
|
||||
for (var j=0; j<opcode.args.length; j++) {
|
||||
param = opcode.args[j];
|
||||
if (typeof param === "string") {
|
||||
param = "\"" + param.replace("\n", "\\n") + "\"";
|
||||
}
|
||||
params.push(param);
|
||||
}
|
||||
out.push(opcode.opcode + " " + params.join(" "));
|
||||
}
|
||||
}
|
||||
|
||||
return out.join("\n");
|
||||
},
|
||||
|
||||
equals: function(other) {
|
||||
var len = this.opcodes.length;
|
||||
if (other.opcodes.length !== len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
var opcode = this.opcodes[i],
|
||||
otherOpcode = other.opcodes[i];
|
||||
if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
|
||||
return false;
|
||||
}
|
||||
for (var j = 0; j < opcode.args.length; j++) {
|
||||
if (opcode.args[j] !== otherOpcode.args[j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len = this.children.length;
|
||||
if (other.children.length !== len) {
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!this.children[i].equals(other.children[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
guid: 0,
|
||||
|
||||
compile: function(program, options) {
|
||||
this.opcodes = [];
|
||||
this.children = [];
|
||||
this.depths = {list: []};
|
||||
this.options = options;
|
||||
|
||||
// These changes will propagate to the other compiler components
|
||||
var knownHelpers = this.options.knownHelpers;
|
||||
this.options.knownHelpers = {
|
||||
'helperMissing': true,
|
||||
'blockHelperMissing': true,
|
||||
'each': true,
|
||||
'if': true,
|
||||
'unless': true,
|
||||
'with': true,
|
||||
'log': true
|
||||
};
|
||||
if (knownHelpers) {
|
||||
for (var name in knownHelpers) {
|
||||
this.options.knownHelpers[name] = knownHelpers[name];
|
||||
}
|
||||
}
|
||||
|
||||
return this.accept(program);
|
||||
},
|
||||
|
||||
accept: function(node) {
|
||||
var strip = node.strip || {},
|
||||
ret;
|
||||
if (strip.left) {
|
||||
this.opcode('strip');
|
||||
}
|
||||
|
||||
ret = this[node.type](node);
|
||||
|
||||
if (strip.right) {
|
||||
this.opcode('strip');
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
program: function(program) {
|
||||
var statements = program.statements;
|
||||
|
||||
for(var i=0, l=statements.length; i<l; i++) {
|
||||
this.accept(statements[i]);
|
||||
}
|
||||
this.isSimple = l === 1;
|
||||
|
||||
this.depths.list = this.depths.list.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
compileProgram: function(program) {
|
||||
var result = new this.compiler().compile(program, this.options);
|
||||
var guid = this.guid++, depth;
|
||||
|
||||
this.usePartial = this.usePartial || result.usePartial;
|
||||
|
||||
this.children[guid] = result;
|
||||
|
||||
for(var i=0, l=result.depths.list.length; i<l; i++) {
|
||||
depth = result.depths.list[i];
|
||||
|
||||
if(depth < 2) { continue; }
|
||||
else { this.addDepth(depth - 1); }
|
||||
}
|
||||
|
||||
return guid;
|
||||
},
|
||||
|
||||
block: function(block) {
|
||||
var mustache = block.mustache,
|
||||
program = block.program,
|
||||
inverse = block.inverse;
|
||||
|
||||
if (program) {
|
||||
program = this.compileProgram(program);
|
||||
}
|
||||
|
||||
if (inverse) {
|
||||
inverse = this.compileProgram(inverse);
|
||||
}
|
||||
|
||||
var type = this.classifyMustache(mustache);
|
||||
|
||||
if (type === "helper") {
|
||||
this.helperMustache(mustache, program, inverse);
|
||||
} else if (type === "simple") {
|
||||
this.simpleMustache(mustache);
|
||||
|
||||
// now that the simple mustache is resolved, we need to
|
||||
// evaluate it by executing `blockHelperMissing`
|
||||
this.opcode('pushProgram', program);
|
||||
this.opcode('pushProgram', inverse);
|
||||
this.opcode('emptyHash');
|
||||
this.opcode('blockValue');
|
||||
} else {
|
||||
this.ambiguousMustache(mustache, program, inverse);
|
||||
|
||||
// now that the simple mustache is resolved, we need to
|
||||
// evaluate it by executing `blockHelperMissing`
|
||||
this.opcode('pushProgram', program);
|
||||
this.opcode('pushProgram', inverse);
|
||||
this.opcode('emptyHash');
|
||||
this.opcode('ambiguousBlockValue');
|
||||
}
|
||||
|
||||
this.opcode('append');
|
||||
},
|
||||
|
||||
hash: function(hash) {
|
||||
var pairs = hash.pairs, pair, val;
|
||||
|
||||
this.opcode('pushHash');
|
||||
|
||||
for(var i=0, l=pairs.length; i<l; i++) {
|
||||
pair = pairs[i];
|
||||
val = pair[1];
|
||||
|
||||
if (this.options.stringParams) {
|
||||
if(val.depth) {
|
||||
this.addDepth(val.depth);
|
||||
}
|
||||
this.opcode('getContext', val.depth || 0);
|
||||
this.opcode('pushStringParam', val.stringModeValue, val.type);
|
||||
} else {
|
||||
this.accept(val);
|
||||
}
|
||||
|
||||
this.opcode('assignToHash', pair[0]);
|
||||
}
|
||||
this.opcode('popHash');
|
||||
},
|
||||
|
||||
partial: function(partial) {
|
||||
var partialName = partial.partialName;
|
||||
this.usePartial = true;
|
||||
|
||||
if(partial.context) {
|
||||
this.ID(partial.context);
|
||||
} else {
|
||||
this.opcode('push', 'depth0');
|
||||
}
|
||||
|
||||
this.opcode('invokePartial', partialName.name);
|
||||
this.opcode('append');
|
||||
},
|
||||
|
||||
content: function(content) {
|
||||
this.opcode('appendContent', content.string);
|
||||
},
|
||||
|
||||
mustache: function(mustache) {
|
||||
var options = this.options;
|
||||
var type = this.classifyMustache(mustache);
|
||||
|
||||
if (type === "simple") {
|
||||
this.simpleMustache(mustache);
|
||||
} else if (type === "helper") {
|
||||
this.helperMustache(mustache);
|
||||
} else {
|
||||
this.ambiguousMustache(mustache);
|
||||
}
|
||||
|
||||
if(mustache.escaped && !options.noEscape) {
|
||||
this.opcode('appendEscaped');
|
||||
} else {
|
||||
this.opcode('append');
|
||||
}
|
||||
},
|
||||
|
||||
ambiguousMustache: function(mustache, program, inverse) {
|
||||
var id = mustache.id,
|
||||
name = id.parts[0],
|
||||
isBlock = program != null || inverse != null;
|
||||
|
||||
this.opcode('getContext', id.depth);
|
||||
|
||||
this.opcode('pushProgram', program);
|
||||
this.opcode('pushProgram', inverse);
|
||||
|
||||
this.opcode('invokeAmbiguous', name, isBlock);
|
||||
},
|
||||
|
||||
simpleMustache: function(mustache) {
|
||||
var id = mustache.id;
|
||||
|
||||
if (id.type === 'DATA') {
|
||||
this.DATA(id);
|
||||
} else if (id.parts.length) {
|
||||
this.ID(id);
|
||||
} else {
|
||||
// Simplified ID for `this`
|
||||
this.addDepth(id.depth);
|
||||
this.opcode('getContext', id.depth);
|
||||
this.opcode('pushContext');
|
||||
}
|
||||
|
||||
this.opcode('resolvePossibleLambda');
|
||||
},
|
||||
|
||||
helperMustache: function(mustache, program, inverse) {
|
||||
var params = this.setupFullMustacheParams(mustache, program, inverse),
|
||||
name = mustache.id.parts[0];
|
||||
|
||||
if (this.options.knownHelpers[name]) {
|
||||
this.opcode('invokeKnownHelper', params.length, name);
|
||||
} else if (this.options.knownHelpersOnly) {
|
||||
throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
|
||||
} else {
|
||||
this.opcode('invokeHelper', params.length, name);
|
||||
}
|
||||
},
|
||||
|
||||
ID: function(id) {
|
||||
this.addDepth(id.depth);
|
||||
this.opcode('getContext', id.depth);
|
||||
|
||||
var name = id.parts[0];
|
||||
if (!name) {
|
||||
this.opcode('pushContext');
|
||||
} else {
|
||||
this.opcode('lookupOnContext', id.parts[0]);
|
||||
}
|
||||
|
||||
for(var i=1, l=id.parts.length; i<l; i++) {
|
||||
this.opcode('lookup', id.parts[i]);
|
||||
}
|
||||
},
|
||||
|
||||
DATA: function(data) {
|
||||
this.options.data = true;
|
||||
if (data.id.isScoped || data.id.depth) {
|
||||
throw new Exception('Scoped data references are not supported: ' + data.original);
|
||||
}
|
||||
|
||||
this.opcode('lookupData');
|
||||
var parts = data.id.parts;
|
||||
for(var i=0, l=parts.length; i<l; i++) {
|
||||
this.opcode('lookup', parts[i]);
|
||||
}
|
||||
},
|
||||
|
||||
STRING: function(string) {
|
||||
this.opcode('pushString', string.string);
|
||||
},
|
||||
|
||||
INTEGER: function(integer) {
|
||||
this.opcode('pushLiteral', integer.integer);
|
||||
},
|
||||
|
||||
BOOLEAN: function(bool) {
|
||||
this.opcode('pushLiteral', bool.bool);
|
||||
},
|
||||
|
||||
comment: function() {},
|
||||
|
||||
// HELPERS
|
||||
opcode: function(name) {
|
||||
this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
|
||||
},
|
||||
|
||||
declare: function(name, value) {
|
||||
this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
|
||||
},
|
||||
|
||||
addDepth: function(depth) {
|
||||
if(isNaN(depth)) { throw new Error("EWOT"); }
|
||||
if(depth === 0) { return; }
|
||||
|
||||
if(!this.depths[depth]) {
|
||||
this.depths[depth] = true;
|
||||
this.depths.list.push(depth);
|
||||
}
|
||||
},
|
||||
|
||||
classifyMustache: function(mustache) {
|
||||
var isHelper = mustache.isHelper;
|
||||
var isEligible = mustache.eligibleHelper;
|
||||
var options = this.options;
|
||||
|
||||
// if ambiguous, we can possibly resolve the ambiguity now
|
||||
if (isEligible && !isHelper) {
|
||||
var name = mustache.id.parts[0];
|
||||
|
||||
if (options.knownHelpers[name]) {
|
||||
isHelper = true;
|
||||
} else if (options.knownHelpersOnly) {
|
||||
isEligible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isHelper) { return "helper"; }
|
||||
else if (isEligible) { return "ambiguous"; }
|
||||
else { return "simple"; }
|
||||
},
|
||||
|
||||
pushParams: function(params) {
|
||||
var i = params.length, param;
|
||||
|
||||
while(i--) {
|
||||
param = params[i];
|
||||
|
||||
if(this.options.stringParams) {
|
||||
if(param.depth) {
|
||||
this.addDepth(param.depth);
|
||||
}
|
||||
|
||||
this.opcode('getContext', param.depth || 0);
|
||||
this.opcode('pushStringParam', param.stringModeValue, param.type);
|
||||
} else {
|
||||
this[param.type](param);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setupMustacheParams: function(mustache) {
|
||||
var params = mustache.params;
|
||||
this.pushParams(params);
|
||||
|
||||
if(mustache.hash) {
|
||||
this.hash(mustache.hash);
|
||||
} else {
|
||||
this.opcode('emptyHash');
|
||||
}
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
// this will replace setupMustacheParams when we're done
|
||||
setupFullMustacheParams: function(mustache, program, inverse) {
|
||||
var params = mustache.params;
|
||||
this.pushParams(params);
|
||||
|
||||
this.opcode('pushProgram', program);
|
||||
this.opcode('pushProgram', inverse);
|
||||
|
||||
if(mustache.hash) {
|
||||
this.hash(mustache.hash);
|
||||
} else {
|
||||
this.opcode('emptyHash');
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
|
||||
function precompile(input, options) {
|
||||
if (input == null || (typeof input !== 'string' && input.constructor !== AST.ProgramNode)) {
|
||||
throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
if (!('data' in options)) {
|
||||
options.data = true;
|
||||
}
|
||||
|
||||
var ast = parse(input);
|
||||
var environment = new Compiler().compile(ast, options);
|
||||
return new JavaScriptCompiler().compile(environment, options);
|
||||
}
|
||||
|
||||
__exports__.precompile = precompile;function compile(input, options, env) {
|
||||
if (input == null || (typeof input !== 'string' && input.constructor !== AST.ProgramNode)) {
|
||||
throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!('data' in options)) {
|
||||
options.data = true;
|
||||
}
|
||||
|
||||
var compiled;
|
||||
|
||||
function compileInput() {
|
||||
var ast = parse(input);
|
||||
var environment = new Compiler().compile(ast, options);
|
||||
var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true);
|
||||
return env.template(templateSpec);
|
||||
}
|
||||
|
||||
// Template is only compiled on first use and cached after that point.
|
||||
return function(context, options) {
|
||||
if (!compiled) {
|
||||
compiled = compileInput();
|
||||
}
|
||||
return compiled.call(this, context, options);
|
||||
};
|
||||
}
|
||||
|
||||
__exports__.compile = compile;
|
||||
return __exports__;
|
||||
})(__module5__, __module8__, __module11__, __module7__);
|
||||
|
||||
// handlebars.js
|
||||
var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
|
||||
"use strict";
|
||||
var __exports__;
|
||||
var Handlebars = __dependency1__;
|
||||
|
||||
// Compiler imports
|
||||
var AST = __dependency2__;
|
||||
var Parser = __dependency3__.parser;
|
||||
var parse = __dependency3__.parse;
|
||||
var Compiler = __dependency4__.Compiler;
|
||||
var compile = __dependency4__.compile;
|
||||
var precompile = __dependency4__.precompile;
|
||||
var JavaScriptCompiler = __dependency5__;
|
||||
|
||||
var _create = Handlebars.create;
|
||||
var create = function() {
|
||||
var hb = _create();
|
||||
|
||||
hb.compile = function(input, options) {
|
||||
return compile(input, options, hb);
|
||||
};
|
||||
hb.precompile = precompile;
|
||||
|
||||
hb.AST = AST;
|
||||
hb.Compiler = Compiler;
|
||||
hb.JavaScriptCompiler = JavaScriptCompiler;
|
||||
hb.Parser = Parser;
|
||||
hb.parse = parse;
|
||||
|
||||
return hb;
|
||||
};
|
||||
|
||||
Handlebars = create();
|
||||
Handlebars.create = create;
|
||||
|
||||
__exports__ = Handlebars;
|
||||
return __exports__;
|
||||
})(__module1__, __module7__, __module8__, __module10__, __module11__);
|
||||
|
||||
return __module0__;
|
||||
})();
|
||||
270
common/static/js/vendor/ova/diacritic-annotator.js
vendored
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
Diacritic Annotator Plugin v1.0 (https://github.com/lduarte1991/diacritic-annotator)
|
||||
Copyright (C) 2014 Luis F Duarte
|
||||
License: https://github.com/lduarte1991/diacritic-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.
|
||||
*/
|
||||
|
||||
var _ref;
|
||||
var __bind = function(fn, me){
|
||||
return function(){
|
||||
return fn.apply(me, arguments);
|
||||
};
|
||||
};
|
||||
var __hasProp = {}.hasOwnProperty;
|
||||
var __extends = function(child, parent) {
|
||||
for (var key in parent) {
|
||||
if (__hasProp.call(parent, key))
|
||||
child[key] = parent[key];
|
||||
}
|
||||
function ctor() { this.constructor = child; }
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor();
|
||||
child.__super__ = parent.prototype;
|
||||
return child;
|
||||
};
|
||||
|
||||
Annotator.Plugin.Diacritics = (function(_super) {
|
||||
__extends(Diacritics, _super);
|
||||
|
||||
//Options will include diacritic name, picture used, baseline
|
||||
Diacritics.prototype.options = null;
|
||||
Diacritics.prototype.diacriticmarks = null;
|
||||
|
||||
/**
|
||||
* Declares all the functions and variables that the plugin will need.
|
||||
* @constructor
|
||||
*/
|
||||
function Diacritics(element,options) {
|
||||
this.pluginSubmit = __bind(this.pluginSubmit, this);
|
||||
this.updateDiacritics = __bind(this.updateDiacritics, this);
|
||||
this.updateViewer = __bind(this.updateViewer, this);
|
||||
this.getDiacritics = __bind(this.getDiacritics, this);
|
||||
this.getPos = __bind(this.getPos, this);
|
||||
this.putMarkAtLocation = __bind(this.putMarkAtLocation, this);
|
||||
this.updateEditorForDiacritics =
|
||||
__bind(this.updateEditorForDiacritics, this);
|
||||
|
||||
this.options = options;
|
||||
this.diacriticmarks = this.getDiacritics();
|
||||
_ref = Diacritics.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
//example variables to be used to receive input in the annotator view
|
||||
Diacritics.prototype.field = null;
|
||||
Diacritics.prototype.input = null;
|
||||
|
||||
/**
|
||||
* Initalizes the Plug-in for diacritic marks. It adds in the field for the mark
|
||||
* and sets up listeners from the Annotator.js file to make changes as needed
|
||||
*/
|
||||
Diacritics.prototype.pluginInit = function() {
|
||||
//Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
var di = this.diacriticmarks;
|
||||
|
||||
//-- Editor
|
||||
var self = this;
|
||||
if(di != 'undefined'){
|
||||
$.each(di,function(item){
|
||||
self.field = self.annotator.editor.addField({
|
||||
//options (textarea,input,select,checkbox)
|
||||
type: 'checkbox',
|
||||
label: Annotator._t(item),
|
||||
submit: self.pluginSubmit,
|
||||
});
|
||||
});
|
||||
|
||||
//-- Viewer
|
||||
this.annotator.viewer.addField({
|
||||
load: this.updateViewer,
|
||||
});
|
||||
|
||||
this.annotator.subscribe('annotationsLoaded', this.updateDiacritics);
|
||||
this.annotator.subscribe('annotationUploaded', this.updateDiacritics);
|
||||
this.annotator.subscribe('annotationDeleted', this.updateDiacritics);
|
||||
this.annotator.subscribe('annotationUpdated', this.updateDiacritics);
|
||||
this.annotator.subscribe('annotationEditorShown', this.updateEditorForDiacritics, this.field);
|
||||
|
||||
$(window).resize(this.updateDiacritics.bind(this));
|
||||
}
|
||||
|
||||
return this.input = $(this.field).find(':input');
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds or removes tag from checked/unchecked boxes of diacritics available
|
||||
* @param field {Object} - element which holds editor
|
||||
* @param annotation {Object} - object that contains annotation information from database
|
||||
*/
|
||||
Diacritics.prototype.pluginSubmit = function(field, annotation) {
|
||||
var checkedItems = $(this.field).find(':input');
|
||||
var self = this;
|
||||
$.each(checkedItems, function(item){
|
||||
if(typeof annotation.tags != 'undefined'){
|
||||
var index = $.inArray(checkedItems[item].placeholder, annotation.tags);
|
||||
if(index != -1){
|
||||
annotation.tags.splice(index, 1);
|
||||
var annotatorWrapper = $('.annotator-wrapper').first();
|
||||
var element = annotatorWrapper.find('div.' + annotation.id);
|
||||
|
||||
if(!element.length){
|
||||
element = annotatorWrapper.find('div.undefined');
|
||||
}
|
||||
|
||||
element.remove();
|
||||
}
|
||||
|
||||
if(checkedItems[item].checked === true){
|
||||
annotation.tags.unshift(checkedItems[item].placeholder);
|
||||
self.putMarkAtLocation(annotation, checkedItems[item].placeholder);
|
||||
}
|
||||
} else {
|
||||
if(checkedItems[item].checked === true){
|
||||
annotation.tags = [checkedItems[item].placeholder];
|
||||
self.putMarkAtLocation(annotation, checkedItems[item].placeholder);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws the mark above a specific annotation
|
||||
* @param annotation {Object} - location where mark should go
|
||||
* @param mark {string}- type of mark that should go above annotation
|
||||
*/
|
||||
Diacritics.prototype.putMarkAtLocation = function (annotation, mark){
|
||||
var loc = this.getPos(annotation.highlights[0]);
|
||||
var alignment = this.diacriticmarks[mark][1];
|
||||
var imgurl = this.diacriticmarks[mark][0];
|
||||
|
||||
var top;
|
||||
switch(alignment){
|
||||
case 'top':
|
||||
top = (loc.y-5);
|
||||
break;
|
||||
case 'bottom':
|
||||
top = (loc.y + loc.height-5);
|
||||
break;
|
||||
default:
|
||||
top = loc.y;
|
||||
}
|
||||
$('<div></div>').addClass('mark ' + annotation.id).css({
|
||||
'top': top,
|
||||
'left': loc.x + (0.5 * loc.width) - 5,
|
||||
'background-image': 'url(' + imgurl +')',
|
||||
}).appendTo('.annotator-wrapper');
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the Diacritics from the instantiation in studio
|
||||
* @returns An object with the diacritics instantiated
|
||||
*/
|
||||
Diacritics.prototype.getDiacritics = function(){
|
||||
var diacritics = {};
|
||||
var diacriticsList;
|
||||
if(typeof this.options.diacritics != 'undefined'){
|
||||
diacriticsList = this.options.diacritics.split(",");
|
||||
$.each(diacriticsList, function(key, item){
|
||||
var temp = item.split(";");
|
||||
if (temp.length > 2) {
|
||||
diacritics[temp[0]] = [temp[1], temp[2]];
|
||||
}
|
||||
});
|
||||
}
|
||||
return diacritics;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the position of a specific element given the wrapper
|
||||
* @param el {Object} - element you are trying to get the position of
|
||||
*/
|
||||
Diacritics.prototype.getPos = function(el) {
|
||||
var element = $(el),
|
||||
elementOffset = element.offset(),
|
||||
annotatorOffset = $('.annotator-wrapper').offset();
|
||||
|
||||
return {
|
||||
x: elementOffset.left - annotatorOffset.left,
|
||||
y: elementOffset.top - annotatorOffset.top,
|
||||
width: element.width(),
|
||||
height: element.height()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Redraws the marks above annotations by cycling through tags
|
||||
*/
|
||||
Diacritics.prototype.updateDiacritics = function(){
|
||||
$('.mark').remove();
|
||||
var annotations = this.annotator.plugins.Store.annotations;
|
||||
var self = this;
|
||||
$.each(annotations, function(key, annotation){
|
||||
$.each(self.diacriticmarks, function(tag){
|
||||
if($.inArray(tag, annotation.tags) != -1){
|
||||
self.putMarkAtLocation(annotation, tag);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes unnecessary field that Annotator automatically adds to popup
|
||||
* @param {Object} field - the html element that represents the popup
|
||||
* @param {Object} annotation - the annotation element that holds metadata
|
||||
*/
|
||||
Diacritics.prototype.updateViewer = function(field, annotation){
|
||||
$(field).remove();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function for adding Diacritic choices to the annotator popup
|
||||
* @param {Object} field - the html element that represents the popup
|
||||
* @param {Object} annotation - the annotation element that holds metadata
|
||||
*/
|
||||
Diacritics.prototype.updateEditorForDiacritics =
|
||||
function(field, annotation){
|
||||
|
||||
// if no tags are present, no need to go through this
|
||||
if (typeof annotation.tags == 'undefined'){
|
||||
return;
|
||||
}
|
||||
|
||||
var inputItems = $(this.field).find(':input');
|
||||
var dictOfItems = {};
|
||||
var self = this;
|
||||
|
||||
// add each diacritic mark to a dictionary and default to off
|
||||
$.each(inputItems, function(key,item){
|
||||
item.checked = false;
|
||||
dictOfItems[item.placeholder] = item;
|
||||
});
|
||||
|
||||
// match tags to diacritics and check off the ones that are true
|
||||
$.each(annotation.tags, function(key,tag){
|
||||
if(self.diacriticmarks[tag]){
|
||||
dictOfItems[tag].checked = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return Diacritics;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
238
common/static/js/vendor/ova/flagging-annotator.js
vendored
@@ -1,238 +0,0 @@
|
||||
var _ref,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Flagging = (function(_super) {
|
||||
__extends(Flagging, _super);
|
||||
|
||||
Flagging.prototype.options = null;
|
||||
|
||||
// declaration function, remember to set up submit and/or update as necessary, if you don't have
|
||||
// options, delete the options line below.
|
||||
function Flagging(element,options) {
|
||||
this.updateViewer = __bind(this.updateViewer, this);
|
||||
this.updateField = __bind(this.updateField, this);
|
||||
this.submitField = __bind(this.submitField, this);
|
||||
this.flagAnnotation = __bind(this.flagAnnotation, this);
|
||||
this.unflagAnnotation = __bind(this.unflagAnnotation, this);
|
||||
this.getTotalFlaggingTags = __bind(this.getTotalFlaggingTags, this);
|
||||
this.options = options;
|
||||
_ref = Flagging.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
// variables to be used to receive input in the annotator view
|
||||
Flagging.prototype.field = null;
|
||||
Flagging.prototype.input = null;
|
||||
Flagging.prototype.hasPressed = false;
|
||||
Flagging.prototype.activeAnnotation = null;
|
||||
Flagging.prototype.mixedTags = null;
|
||||
|
||||
// this function will initialize the plug-in
|
||||
Flagging.prototype.pluginInit = function() {
|
||||
console.log("Flagging-pluginInit");
|
||||
|
||||
// Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// -- Editor
|
||||
//creates a checkbox to remove all flags
|
||||
var self = this;
|
||||
this.field = this.annotator.editor.addField({
|
||||
type: 'checkbox',
|
||||
load: this.updateField,
|
||||
// Translators: please note that this is not a literal flag, but rather a report
|
||||
label: Annotator._t(gettext('Check the box to remove all flags.')),
|
||||
submit: this.submitField,
|
||||
});
|
||||
|
||||
// -- Viewer
|
||||
var newview = this.annotator.viewer.addField({
|
||||
load: this.updateViewer,
|
||||
});
|
||||
|
||||
return this.input = $(this.field).find(':input');
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the total number of tags associated with the flagging tool.
|
||||
* @param {Object} annotation Annotation item from Annotator.
|
||||
*/
|
||||
Flagging.prototype.getTotalFlaggingTags = function(annotation){
|
||||
var tags = (typeof annotation.tags !== 'undefined') ? annotation.tags.slice() : [];
|
||||
// Goes through and gets the number of tags that contained the keyword "flagged"
|
||||
return $.grep(tags, function(tag, index){
|
||||
return (tag.indexOf('flagged') !== -1);
|
||||
}).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new field in the editor in order to delete the flagged tags.
|
||||
* @param {HTMLElement} field The HTML element contained in the editor reserved for flagging.
|
||||
* @param {Object} annotation Annotation item from Annotator.
|
||||
*/
|
||||
Flagging.prototype.updateField = function(field, annotation) {
|
||||
|
||||
// figure out whether annotation is of type image or if ova is not defined (meaning it
|
||||
// it doesn't have a type yet, but it is still an image).
|
||||
var user_email = (annotation.media === "image" || typeof ova === 'undefined') ?
|
||||
osda.options.optionsAnnotator.permissions.user.id:
|
||||
ova.options.optionsAnnotator.permissions.user.id;
|
||||
|
||||
// get total number of flag tags as well as save a copy of the mixed tags
|
||||
var totalFlags = this.getTotalFlaggingTags(annotation);
|
||||
this.mixedTags = annotation.tags;
|
||||
var self = this;
|
||||
|
||||
// only show this field if you are an instructor and there are flags to remove
|
||||
if(Catch.options.instructor_email === user_email && totalFlags > 0){
|
||||
// Translators: 'totalFlags' is the number of flags solely for that annotation
|
||||
var message = ngettext("Check the box to remove %(totalFlags)s flag.", "Check the box to remove %(totalFlags)s flags.", totalFlags);
|
||||
$(field).find('label')[0].innerHTML = interpolate(message, {totalFlags : totalFlags}, true);
|
||||
this.activeAnnotation = annotation;
|
||||
|
||||
// add function to change the text when the user checks the box or removes the check
|
||||
$(field).find('input').change(function(evt){
|
||||
if(!$(field).find('input:checkbox:checked').val()){
|
||||
var count = self.getTotalFlaggingTags(self.activeAnnotation);
|
||||
// Translators: 'count' is the number of flags solely for that annotation that will be removed
|
||||
var message = ngettext("Check the box to remove %(count)s flag.", "Check the box to remove %(count)s flags.", count)
|
||||
$(field).find('label')[0].innerHTML = interpolate(message, {count: count}, true);
|
||||
} else {
|
||||
$(field).find('label')[0].innerHTML = gettext("All flags have been removed. To undo, uncheck the box.");
|
||||
}
|
||||
});
|
||||
$(field).show();
|
||||
} else {
|
||||
$(field).hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes last-minute changes to the annotation right before it is saved in the server.
|
||||
* @param {HTMLElement} field The HTML element contained in the editor reserved for flagging.
|
||||
* @param {Object} annotation Annotation item from Annotator.
|
||||
*/
|
||||
Flagging.prototype.submitField = function(field, annotation) {
|
||||
// if the user did not check the box go back and input all of the tags.
|
||||
if (!$(field).find('input:checkbox:checked').val()){
|
||||
annotation.tags = this.mixedTags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The following allows you to edit the annotation popup when the viewer has already
|
||||
* hit submit and is just viewing the annotation.
|
||||
* @param {HTMLElement} field The HTML element contained in the editor reserved for flagging.
|
||||
* @param {Object} annotation Annotation item from Annotator.
|
||||
*/
|
||||
Flagging.prototype.updateViewer = function(field, annotation) {
|
||||
var self = this;
|
||||
this.hasPressed = false;
|
||||
|
||||
// perform routine to check if user has pressed the button before
|
||||
var tags = typeof annotation.tags != 'undefined'?annotation.tags:[];
|
||||
var user = this.annotator.plugins.Permissions.user.id;
|
||||
tags.forEach(function(t){
|
||||
if (t.indexOf("flagged")>=0) {
|
||||
var usertest = t.replace('flagged-','');
|
||||
if (usertest == user)
|
||||
self.hasPressed = true;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// changes display based on check done above
|
||||
var fieldControl = $(this.annotator.viewer.element.find('.annotator-controls')).parent();
|
||||
if (this.hasPressed) {
|
||||
|
||||
// make sure to use id when searching for the item so that only one of them gets changed
|
||||
var message = gettext("You have already reported this annotation.");
|
||||
fieldControl.prepend('<button title="' + message + '" class="flag-icon-used" id="' + annotation.id + '">');
|
||||
|
||||
var flagEl = fieldControl.find('.flag-icon-used#' + annotation.id);
|
||||
var self = this;
|
||||
|
||||
// sets function to unflag after next click
|
||||
flagEl.click(function(){self.unflagAnnotation(annotation,user,flagEl,field)});
|
||||
|
||||
} else{
|
||||
|
||||
// likewise, make sure to use id when searching for the item so that only one is changed
|
||||
var message = gettext("Report annotation as inappropriate or offensive.");
|
||||
fieldControl.prepend('<button title="' + message + '" class="flag-icon" id="' + annotation.id + '">');
|
||||
|
||||
var flagEl = fieldControl.find('.flag-icon#' + annotation.id);
|
||||
var self = this;
|
||||
|
||||
// sets function to flag after next click
|
||||
flagEl.click(function(){self.flagAnnotation(annotation,user,flagEl,field)});
|
||||
}
|
||||
|
||||
var user_email = annotation.media === "image" ?
|
||||
osda.options.optionsAnnotator.permissions.user.id:
|
||||
ova.options.optionsAnnotator.permissions.user.id;
|
||||
var totalFlags = this.getTotalFlaggingTags(annotation);
|
||||
|
||||
// only show the number of times an annotation has been flagged if they are the instructors
|
||||
if(Catch.options.instructor_email === user_email && totalFlags > 0){
|
||||
// Translators: 'count' is the number of flags solely for that annotation
|
||||
var message = ngettext("This annotation has %(count)s flag.","This annotation has %(count)s flags.", totalFlags);
|
||||
$(field).append("<div class=\"flag-count\">" + interpolate(message, {count : totalFlags}, true) + "</div>");
|
||||
} else {
|
||||
$(field).remove(); // remove the empty div created by annotator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function changes the visual aspects of flagging an Annotation and sends changes
|
||||
* to the database backend.
|
||||
*/
|
||||
Flagging.prototype.flagAnnotation = function(annotation, userId, flagElement, field) {
|
||||
|
||||
// changes the class and title to show user's flagging action worked
|
||||
flagElement.attr("class","flag-icon-used");
|
||||
flagElement.attr("title", gettext("You have already reported this annotation."));
|
||||
|
||||
// it adds the appropriate tag with the user name to make sure it is added
|
||||
if (typeof annotation.tags == 'undefined') {
|
||||
annotation.tags = ['flagged-'+userId];
|
||||
} else{
|
||||
annotation.tags.push("flagged-"+userId);
|
||||
}
|
||||
|
||||
// annotation gets updated and a warning is published that an annotation has been flagged
|
||||
this.annotator.plugins['Store'].annotationUpdated(annotation);
|
||||
this.annotator.publish("flaggedAnnotation",[field,annotation]);
|
||||
|
||||
// now that it is flagged, it sets the click function to unflag
|
||||
flagElement.click(function(){self.unflagAnnotation(annotation,userId,flagElement,field)});
|
||||
}
|
||||
|
||||
/**
|
||||
* This function changes the visual aspects of unflagging an Annotation and sends changes
|
||||
* to the database backend.
|
||||
*/
|
||||
Flagging.prototype.unflagAnnotation = function(annotation, userId, flagElement, field) {
|
||||
|
||||
// changes the class and title to show user's unflagging action worked
|
||||
flagElement.attr("class", "flag-icon");
|
||||
flagElement.attr("title", gettext("Report annotation as inappropriate or offensive."));
|
||||
|
||||
// it removes the tag that signifies flagging
|
||||
annotation.tags.splice(annotation.tags.indexOf('flagged-'+userId));
|
||||
|
||||
// annotation gets updated without the tag and a warning is published that flagging is changed
|
||||
this.annotator.plugins['Store'].annotationUpdated(annotation);
|
||||
this.annotator.publish("flaggedAnnotation",[field,annotation]);
|
||||
|
||||
// now that it is unflagged, it sets the click function to flag
|
||||
flagElement.click(function(){self.unflagAnnotation(annotation,userId,flagElement,field)});
|
||||
}
|
||||
|
||||
return Flagging;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
279
common/static/js/vendor/ova/grouping-annotator.js
vendored
@@ -1,279 +0,0 @@
|
||||
var _ref;
|
||||
var __bind = function(fn, me) {
|
||||
return function() {
|
||||
return fn.apply(me, arguments);
|
||||
};
|
||||
};
|
||||
var __hasProp = {}.hasOwnProperty;
|
||||
var __extends = function(child, parent) {
|
||||
for (var key in parent) {
|
||||
if (__hasProp.call(parent, key))
|
||||
child[key] = parent[key];
|
||||
}
|
||||
function ctor() {
|
||||
this.constructor = child;
|
||||
}
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor();
|
||||
child.__super__ = parent.prototype;
|
||||
return child;
|
||||
};
|
||||
|
||||
Annotator.Plugin.Grouping = (function(_super) {
|
||||
__extends(Grouping, _super);
|
||||
|
||||
// this plugin will have a threshold option (-1 = plugin should be removed)
|
||||
Grouping.prototype.options = null;
|
||||
|
||||
// sets up the grouping structure for the plug-in
|
||||
function Grouping(element, options) {
|
||||
this.pluginInit = __bind(this.pluginInit, this);
|
||||
this.reloadAnnotations = __bind(this.reloadAnnotations, this);
|
||||
this.groupAndColor = __bind(this.groupAndColor, this);
|
||||
this.clearGrouping = __bind(this.clearGrouping, this);
|
||||
this.getPos = __bind(this.getPos, this);
|
||||
this.groupingButtonPressed = __bind(this.groupingButtonPressed, this);
|
||||
this.options = options;
|
||||
_ref = Grouping.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
// instantiation of variables to be passed around below
|
||||
Grouping.prototype.unfilteredAnnotations = null;
|
||||
Grouping.prototype.groupedAnnotations = null;
|
||||
Grouping.prototype.groupthreshold = 0;
|
||||
Grouping.prototype.useGrouping = 1;
|
||||
|
||||
/**
|
||||
* Gets the current position relative to the annotation wrapper
|
||||
* @param {HTMLElement} el Element (assumed to be within annotator-wrapper) being measured.
|
||||
* @return {Object} Position of element passed in using x, y coordinates
|
||||
*/
|
||||
Grouping.prototype.getPos = function(el) {
|
||||
// gets the offset of the element and wrapper
|
||||
var off = $(el).offset();
|
||||
var wrapperOff = $($('.annotator-wrapper')[0]).offset();
|
||||
|
||||
// do height calculations from the wrapper
|
||||
return {x:off.left, y:off.top-wrapperOff.top};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the plugin and its attributes.
|
||||
*/
|
||||
Grouping.prototype.pluginInit = function() {
|
||||
// Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
console.log("Annotator is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
// makes sure that every time a change is made to annotations, the grouping is redone
|
||||
this.annotator.subscribe('annotationsLoaded', this.reloadAnnotations);
|
||||
this.annotator.subscribe('annotationUploaded', this.reloadAnnotations);
|
||||
this.annotator.subscribe('annotationDeleted', this.reloadAnnotations);
|
||||
this.annotator.subscribe('annotationCreated', this.reloadAnnotations);
|
||||
this.annotator.subscribe('changedTabsInCatch', this.groupingButtonPressed);
|
||||
|
||||
// sets up the button that toggles the grouping on or off
|
||||
var newdiv = document.createElement('div');
|
||||
var className = 'onOffGroupButton';
|
||||
newdiv.setAttribute('class', className);
|
||||
|
||||
// if the item is in public then it should default to grouping being on
|
||||
if (options.optionsOVA.default_tab.toLowerCase() === 'public') {
|
||||
newdiv.innerHTML = "Annotation Grouping: ON";
|
||||
this.useGrouping = 1;
|
||||
// we wait for HighlightTags to complete before reloading annotations
|
||||
this.annotator.subscribe('colorizeCompleted', this.reloadAnnotations);
|
||||
} else {
|
||||
newdiv.innerHTML = "Annotation Grouping: OFF";
|
||||
$(newdiv).addClass('buttonOff');
|
||||
this.useGrouping = 0;
|
||||
}
|
||||
$($('.annotator-wrapper')[0]).prepend(newdiv);
|
||||
$(newdiv).click(this.groupingButtonPressed);
|
||||
|
||||
// makes sure that if user resizes window, the annotations are regrouped
|
||||
var self = this;
|
||||
$(window).resize(function() {
|
||||
self.reloadAnnotations();//resize just happened, pixels changed
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function that removes all of the side buttons and sets background to yellow
|
||||
*/
|
||||
Grouping.prototype.clearGrouping = function() {
|
||||
$('.groupButton').remove();
|
||||
$.each(this.unfilteredAnnotations, function(val) {
|
||||
if (val.highlights !== undefined){
|
||||
$.each(val.highlights, function(high){
|
||||
$(high).css("background-color", "inherit");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that goes through and groups together annotations on the same line
|
||||
*/
|
||||
Grouping.prototype.groupAndColor = function() {
|
||||
annotations = this.unfilteredAnnotations;
|
||||
lineAnnDict = {};
|
||||
var self = this;
|
||||
|
||||
// for each annotation, if they have highlights, get the positions and add them
|
||||
// to a dictionary based on its initial line location
|
||||
annotations.forEach(function(annot) {
|
||||
if (annot.highlights !== undefined) {
|
||||
var loc = Math.round(self.getPos(annot.highlights[0]).y);
|
||||
if (lineAnnDict[loc] === undefined) {
|
||||
lineAnnDict[loc] = [annot];
|
||||
return;
|
||||
} else {
|
||||
lineAnnDict[loc].push(annot);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.groupedAnnotations = null;
|
||||
this.groupedAnnotations = lineAnnDict;
|
||||
|
||||
// Then it goes through and sets the color based on the threshold set
|
||||
var self = this;
|
||||
$.each(lineAnnDict, function(key, val) {
|
||||
if (val.length > self.groupthreshold) {
|
||||
val.forEach(function(anno){
|
||||
if (anno.highlights !== undefined) {
|
||||
$.each(anno.highlights, function(key, anno) {
|
||||
$(anno).css("background-color", "inherit");
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
val.forEach(function(anno) {
|
||||
if (anno.highlights !== undefined) {
|
||||
$.each(anno.highlights, function(key, anno) {
|
||||
$(anno).css("background-color", "rgba(255, 255, 10, .3)");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that clears old groupings, regroups, and adds the side buttons.
|
||||
*/
|
||||
Grouping.prototype.reloadAnnotations = function() {
|
||||
var annotations = this.annotator.plugins['Store'].annotations;
|
||||
// clear the sidebuttons
|
||||
this.unfilteredAnnotations = annotations;
|
||||
this.clearGrouping();
|
||||
if (this.useGrouping === 0) {
|
||||
return;
|
||||
}
|
||||
this.groupAndColor();
|
||||
var self = this;
|
||||
|
||||
// The following creates a sidebutton that is based on line location. it will
|
||||
// contain a number referring to the number of hidden annotations
|
||||
$.each(this.groupedAnnotations, function(key, val) {
|
||||
if (val.length > self.groupthreshold) {
|
||||
var newdiv = document.createElement('div');
|
||||
var className = 'groupButton';
|
||||
newdiv.setAttribute('class', className);
|
||||
$(newdiv).css('top', "" + key + "px");
|
||||
newdiv.innerHTML = val.length;
|
||||
$(newdiv).attr('data-selected', '0');
|
||||
$('.annotator-wrapper')[0].appendChild(newdiv);
|
||||
$(newdiv).click(function(evt){
|
||||
if($(evt.srcElement).attr("data-selected") === '0') {
|
||||
annotations.forEach(function(annot){
|
||||
if (annot.highlights !== undefined) {
|
||||
$.each(annot.highlights, function(key, ann) {
|
||||
$(ann).css("background-color", "inherit");
|
||||
});
|
||||
}
|
||||
});
|
||||
self.groupedAnnotations[$(evt.srcElement).css("top").replace("px", "")].forEach(function(item) {
|
||||
if (item.highlights !== undefined) {
|
||||
$.each(item.highlights, function(key, ann) {
|
||||
$(ann).css("background-color", "rgba(255, 255, 10, 0.3)");
|
||||
});
|
||||
}
|
||||
});
|
||||
$(evt.srcElement).attr("data-selected", '1');
|
||||
} else {
|
||||
annotations.forEach(function(item) {
|
||||
$(item).css("background-color", "inherit");
|
||||
});
|
||||
self.groupAndColor();
|
||||
$(evt.srcElement).attr("data-selected", '0');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
var self = this;
|
||||
var old = self.unfilteredAnnotations.length;
|
||||
setTimeout(function() {
|
||||
if (old !== self.unfilteredAnnotations.length) {
|
||||
self.reloadAnnotations();
|
||||
}
|
||||
}, 500);
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function activated to turn grouping on or off
|
||||
*/
|
||||
Grouping.prototype.groupingButtonPressed = function() {
|
||||
if(this.useGrouping === 1) {
|
||||
|
||||
// grouping is cleared
|
||||
this.useGrouping = 0;
|
||||
this.clearGrouping();
|
||||
|
||||
// remove the grouping functions from being activated by events
|
||||
this.annotator.unsubscribe('annotationsLoaded', this.reloadAnnotations);
|
||||
this.annotator.unsubscribe('annotationUploaded', this.reloadAnnotations);
|
||||
this.annotator.unsubscribe('annotationDeleted', this.reloadAnnotations);
|
||||
this.annotator.unsubscribe('annotationCreated', this.reloadAnnotations);
|
||||
|
||||
// redraw button to turn grouping on/off
|
||||
$(".onOffGroupButton").html("Annotation Grouping: OFF");
|
||||
$(".onOffGroupButton").addClass("buttonOff");
|
||||
this.annotator.plugins.Store.annotations.forEach(function(annot) {
|
||||
if (annot.highlights !== undefined) {
|
||||
$.each(annot.highlights, function(key, ann) {
|
||||
$(ann).css("background-color", "");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// deals with the HighlightTags Plug-In
|
||||
this.annotator.publish('externalCallToHighlightTags');
|
||||
this.annotator.unsubscribe('colorizeCompleted', this.reloadAnnotations);
|
||||
} else {
|
||||
|
||||
// runs reload/regroup annotations
|
||||
this.useGrouping = 1;
|
||||
this.reloadAnnotations();
|
||||
|
||||
// subscribe again to the events triggered by annotations
|
||||
this.annotator.subscribe('annotationsLoaded', this.reloadAnnotations);
|
||||
this.annotator.subscribe('annotationUploaded', this.reloadAnnotations);
|
||||
this.annotator.subscribe('annotationDeleted', this.reloadAnnotations);
|
||||
this.annotator.subscribe('annotationCreated', this.reloadAnnotations);
|
||||
|
||||
// redraw button to turn grouping on/off
|
||||
$(".onOffGroupButton").html("Annotation Grouping: ON");
|
||||
$(".onOffGroupButton").removeClass("buttonOff");
|
||||
this.annotator.subscribe('colorizeCompleted', this.reloadAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
return Grouping;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
Before Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 647 B |
|
Before Width: | Height: | Size: 637 B |
BIN
common/static/js/vendor/ova/images/fullpage_rest.png
vendored
|
Before Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 412 B |
BIN
common/static/js/vendor/ova/images/home_hover.png
vendored
|
Before Width: | Height: | Size: 566 B |
BIN
common/static/js/vendor/ova/images/home_pressed.png
vendored
|
Before Width: | Height: | Size: 562 B |
BIN
common/static/js/vendor/ova/images/home_rest.png
vendored
|
Before Width: | Height: | Size: 412 B |
|
Before Width: | Height: | Size: 474 B |
BIN
common/static/js/vendor/ova/images/newan_hover.png
vendored
|
Before Width: | Height: | Size: 668 B |
BIN
common/static/js/vendor/ova/images/newan_pressed.png
vendored
|
Before Width: | Height: | Size: 695 B |
BIN
common/static/js/vendor/ova/images/newan_rest.png
vendored
|
Before Width: | Height: | Size: 474 B |
|
Before Width: | Height: | Size: 396 B |
BIN
common/static/js/vendor/ova/images/next_hover.png
vendored
|
Before Width: | Height: | Size: 568 B |
BIN
common/static/js/vendor/ova/images/next_pressed.png
vendored
|
Before Width: | Height: | Size: 555 B |
BIN
common/static/js/vendor/ova/images/next_rest.png
vendored
|
Before Width: | Height: | Size: 396 B |
|
Before Width: | Height: | Size: 393 B |
|
Before Width: | Height: | Size: 567 B |
|
Before Width: | Height: | Size: 555 B |
BIN
common/static/js/vendor/ova/images/previous_rest.png
vendored
|
Before Width: | Height: | Size: 393 B |
|
Before Width: | Height: | Size: 317 B |
BIN
common/static/js/vendor/ova/images/zoomin_hover.png
vendored
|
Before Width: | Height: | Size: 451 B |
|
Before Width: | Height: | Size: 442 B |
BIN
common/static/js/vendor/ova/images/zoomin_rest.png
vendored
|
Before Width: | Height: | Size: 317 B |
|
Before Width: | Height: | Size: 267 B |
BIN
common/static/js/vendor/ova/images/zoomout_hover.png
vendored
|
Before Width: | Height: | Size: 381 B |
|
Before Width: | Height: | Size: 370 B |
BIN
common/static/js/vendor/ova/images/zoomout_rest.png
vendored
|
Before Width: | Height: | Size: 267 B |
116
common/static/js/vendor/ova/jquery-Watch.js
vendored
@@ -1,116 +0,0 @@
|
||||
/**
|
||||
* jQuery Watch Plugin
|
||||
*
|
||||
* @author Darcy Clarke
|
||||
* @version 2.0
|
||||
*
|
||||
* Copyright (c) 2012 Darcy Clarke
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
*
|
||||
* ADDS:
|
||||
*
|
||||
* - $.watch()
|
||||
*
|
||||
* USES:
|
||||
*
|
||||
* - DOMAttrModified event
|
||||
*
|
||||
* FALLBACKS:
|
||||
*
|
||||
* - propertychange event
|
||||
* - setTimeout() with delay
|
||||
*
|
||||
* EXAMPLE:
|
||||
*
|
||||
* $('div').watch('width height', function(){
|
||||
* console.log(this.style.width, this.style.height);
|
||||
* });
|
||||
*
|
||||
* $('div').animate({width:'100px',height:'200px'}, 500);
|
||||
*
|
||||
*/
|
||||
|
||||
(function($){
|
||||
$.extend($.fn, {
|
||||
/**
|
||||
* Watch Method
|
||||
*
|
||||
* @param {String} the name of the properties to watch
|
||||
* @param {Object} options to overide defaults (only 'throttle' right now)
|
||||
* @param {Function} callback function to be executed when attributes change
|
||||
*
|
||||
* @return {jQuery Object} returns the jQuery object for chainability
|
||||
*/
|
||||
watch : function(props, options, callback){
|
||||
// Dummmy element
|
||||
var element = document.createElement('div');
|
||||
|
||||
/**
|
||||
* Checks Support for Event
|
||||
*
|
||||
* @param {String} the name of the event
|
||||
* @param {Element Object} the element to test support against
|
||||
*
|
||||
* @return {Boolean} returns result of test (true/false)
|
||||
*/
|
||||
var isEventSupported = function(eventName, el) {
|
||||
eventName = 'on' + eventName;
|
||||
var supported = (eventName in el);
|
||||
if(!supported){
|
||||
el.setAttribute(eventName, 'return;');
|
||||
supported = typeof el[eventName] == 'function';
|
||||
}
|
||||
return supported;
|
||||
};
|
||||
// Type check options
|
||||
if(typeof(options) == 'function'){
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
// Type check callback
|
||||
if(typeof(callback) != 'function')
|
||||
callback = function(){};
|
||||
// Map options over defaults
|
||||
options = $.extend({}, { throttle : 10 }, options);
|
||||
/**
|
||||
* Checks if properties have changed
|
||||
*
|
||||
* @param {Element Object} the element to watch
|
||||
*
|
||||
*/
|
||||
var check = function(el) {
|
||||
var data = el.data(),
|
||||
changed = false,
|
||||
temp;
|
||||
|
||||
// Loop through properties
|
||||
var length = typeof data!='undefined' && typeof data.props!='undefined'?data.props.length:0;
|
||||
for(var i=0;i < length; i++){
|
||||
temp = el.css(data.props[i]);
|
||||
if(data.vals[i] != temp){
|
||||
data.vals[i] = temp;
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Run callback if property has changed
|
||||
if(changed && data.cb)
|
||||
data.cb.call(el, data);
|
||||
};
|
||||
return this.each(function(){
|
||||
var el = $(this),
|
||||
cb = function(){ check.call(this, el) },
|
||||
data = { props:props.split(','), cb:callback, vals: [] };
|
||||
$.each(data.props, function(i){ data.vals[i] = el.css(data.props[i]); });
|
||||
el.data(data);
|
||||
if(isEventSupported('DOMAttrModified', element)){
|
||||
el.on('DOMAttrModified', callback);
|
||||
} else if(isEventSupported('propertychange', element)){
|
||||
el.on('propertychange', callback);
|
||||
} else {
|
||||
setInterval(cb, options.throttle);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
12946
common/static/js/vendor/ova/openseadragon.js
vendored
2547
common/static/js/vendor/ova/ova.js
vendored
@@ -1,2547 +0,0 @@
|
||||
/*
|
||||
Open Video Annotation v1.0 (http://openvideoannotation.org/)
|
||||
Copyright (C) 2014 CHS (Harvard University), Daniel Cebrian Robles and Phil Desenne
|
||||
License: https://github.com/CtrHellenicStudies/OpenVideoAnnotation/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.
|
||||
*/
|
||||
// ----------------Utilities---------------- //
|
||||
var _ref;
|
||||
var __bind = function(fn, me) {
|
||||
return function() {
|
||||
return fn.apply(me, arguments);
|
||||
};
|
||||
};
|
||||
var __hasProp = {}.hasOwnProperty;
|
||||
var __extends = function(child, parent) {
|
||||
for (var key in parent) {
|
||||
if (__hasProp.call(parent, key))
|
||||
child[key] = parent[key];
|
||||
}
|
||||
function ctor() {
|
||||
this.constructor = child;
|
||||
}
|
||||
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor();
|
||||
child.__super__ = parent.prototype;
|
||||
return child;
|
||||
};
|
||||
var createDateFromISO8601 = function(string) {
|
||||
var d, date, offset, regexp, time, _ref;
|
||||
regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\\.([0-9]+))?)?" + "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
|
||||
d = string.match(new RegExp(regexp));
|
||||
offset = 0;
|
||||
date = new Date(d[1], 0, 1);
|
||||
if (d[3]) {
|
||||
date.setMonth(d[3] - 1);
|
||||
}
|
||||
if (d[5]) {
|
||||
date.setDate(d[5]);
|
||||
}
|
||||
if (d[7]) {
|
||||
date.setHours(d[7]);
|
||||
}
|
||||
if (d[8]) {
|
||||
date.setMinutes(d[8]);
|
||||
}
|
||||
if (d[10]) {
|
||||
date.setSeconds(d[10]);
|
||||
}
|
||||
if (d[12]) {
|
||||
date.setMilliseconds(Number("0." + d[12]) * 1000);
|
||||
}
|
||||
if (d[14]) {
|
||||
offset = (Number(d[16]) * 60) + Number(d[17]);
|
||||
offset *= (_ref = d[15] === '-') != null ? _ref : {
|
||||
1: -1
|
||||
};
|
||||
}
|
||||
offset -= date.getTimezoneOffset();
|
||||
time = Number(date) + (offset * 60 * 1000);
|
||||
date.setTime(Number(time));
|
||||
return date;
|
||||
};
|
||||
var Util = typeof Util != 'undefined' ? Util : {};
|
||||
Util.mousePosition = function(e, offsetEl) {
|
||||
var offset, _ref1;
|
||||
if ((_ref1 = $(offsetEl).css('position')) !== 'absolute' && _ref1 !== 'fixed' && _ref1 !== 'relative') {
|
||||
offsetEl = $(offsetEl).offsetParent()[0];
|
||||
}
|
||||
offset = $(offsetEl).offset();
|
||||
return {
|
||||
top: e.pageY - offset.top,
|
||||
left: e.pageX - offset.left
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------Load videojs-Annotation Plugin---------------- //
|
||||
(function () {
|
||||
// -- Load Annotation plugin in videojs
|
||||
function vjsAnnotation_(options){
|
||||
var player = this;
|
||||
|
||||
// variables to know if it is ready
|
||||
|
||||
player.annotations = new vjsAnnotation(player, options);
|
||||
|
||||
// When the DOM, Range Slider and the video media is loaded
|
||||
function initialVideoFinished(event) {
|
||||
// -- wait for plugins -- //
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = $.data(wrapper, 'annotator');
|
||||
|
||||
// wait for Annotator and the Share plugin
|
||||
if (typeof Annotator.Plugin["Share"] === 'function') {
|
||||
if (typeof annotator.isShareLoaded != 'undefined' && annotator.isShareLoaded) {
|
||||
annotator.unsubscribe('shareloaded', initialVideoFinished);
|
||||
} else {
|
||||
annotator.subscribe('shareloaded', initialVideoFinished);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var plugin = player.annotations;
|
||||
|
||||
// All components will be initialize after they have been loaded by videojs
|
||||
for (var index in plugin.components) {
|
||||
plugin.components[index].init_();
|
||||
}
|
||||
|
||||
player.annotations.BigNewAn.show();
|
||||
|
||||
// set the position of the big buttom
|
||||
plugin.setposBigNew(plugin.options.posBigNew);
|
||||
|
||||
if(!options.showDisplay)
|
||||
plugin.hideDisplay();
|
||||
if(!options.showStatistics)
|
||||
plugin.hideStatistics();
|
||||
|
||||
|
||||
// Get current instance of annotator
|
||||
player.annotator = annotator;
|
||||
plugin.annotator = annotator;
|
||||
|
||||
// get annotations
|
||||
var allannotations = annotator.plugins['Store'].annotations;
|
||||
plugin.refreshDisplay();
|
||||
|
||||
// -- Listener to Range Slider Plugin
|
||||
player.rangeslider.rstb.on('mousedown', function(){plugin._onMouseDownRS(event)});
|
||||
// Open the autoPlay from the API
|
||||
if (player.autoPlayAPI) {
|
||||
var OnePlay = function () {
|
||||
player.annotations.showAnnotation(player.autoPlayAPI);
|
||||
$('html, body').animate({
|
||||
scrollTop: $("#" + player.id_).offset().top},
|
||||
'slow');
|
||||
};
|
||||
if (player.techName == 'Youtube')
|
||||
setTimeout(OnePlay, 100); // fix the delay playing youtube
|
||||
else
|
||||
OnePlay();
|
||||
}
|
||||
|
||||
// set the number of Annotations to display
|
||||
plugin.refreshDesignPanel();
|
||||
|
||||
// check full-screen change
|
||||
player.on('fullscreenchange', function() {
|
||||
if (player.isFullScreen) {
|
||||
$(player.annotator.wrapper[0]).addClass('vjs-fullscreen');
|
||||
} else {
|
||||
$(player.annotator.wrapper[0]).removeClass('vjs-fullscreen');
|
||||
}
|
||||
plugin.refreshDesignPanel();
|
||||
});
|
||||
|
||||
// loaded plugin
|
||||
plugin.loaded = true;
|
||||
}
|
||||
player.one('loadedRangeSlider', initialVideoFinished); // Loaded RangeSlider
|
||||
|
||||
console.log("Loaded Annotation Plugin");
|
||||
}
|
||||
videojs.plugin('annotations', vjsAnnotation_);
|
||||
|
||||
|
||||
// -- Plugin
|
||||
function vjsAnnotation(player, options) {
|
||||
var player = player || this;
|
||||
|
||||
this.player = player;
|
||||
|
||||
this.components = {}; // holds any custom components we add to the player
|
||||
|
||||
options = options || {}; // plugin options
|
||||
|
||||
if(!options.hasOwnProperty('posBigNew'))
|
||||
options.posBigNew = 'none'; // ul = up left || ur = up right || bl = below left || br = below right || c = center
|
||||
if(!options.hasOwnProperty('showDisplay'))
|
||||
options.showDisplay = false;
|
||||
if(!options.hasOwnProperty('showStatistics'))
|
||||
options.showStatistics = false;
|
||||
|
||||
this.options = options;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
// -- Methods
|
||||
vjsAnnotation.prototype = {
|
||||
/* Constructor */
|
||||
init: function() {
|
||||
var player = this.player || {};
|
||||
var controlBar = player.controlBar;
|
||||
var seekBar = player.controlBar.progressControl.seekBar;
|
||||
|
||||
this.updatePrecision = 3;
|
||||
|
||||
// Components and Quick Aliases
|
||||
this.BigNewAn = this.components.BigNewAnnotation = player.BigNewAnnotation;
|
||||
this.AnConBut = this.components.AnContainerButtons = controlBar.AnContainerButtons;
|
||||
this.ShowSt = this.components.ShowStatistics = this.AnConBut.ShowStatistics;
|
||||
this.NewAn = this.components.NewAnnotation = this.AnConBut.NewAnnotation;
|
||||
this.ShowAn =this.components.ShowAnnotations = this.AnConBut.ShowAnnotations;
|
||||
this.BackAnDisplay = this.components.BackAnDisplay = controlBar.BackAnDisplay; // Background of the panel
|
||||
this.AnDisplay = this.components.AnDisplay = controlBar.BackAnDisplay.AnDisplay; // Panel with all the annotations
|
||||
this.AnStat = this.components.AnStat = controlBar.BackAnDisplay.AnStat; // Panel with statistics of the number of annotations
|
||||
this.BackAnDisplayScroll = this.components.BackAnDisplayScroll = controlBar.BackAnDisplayScroll; // Back Panel with all the annotations
|
||||
this.backDSBar = this.components.BackAnDisplayScrollBar = this.BackAnDisplayScroll.BackAnDisplayScrollBar; // Scroll Bar
|
||||
this.backDSBarSel = this.components.ScrollBarSelector = this.backDSBar.ScrollBarSelector; // Scroll Bar Selector
|
||||
this.backDSTime = this.components.BackAnDisplayScrollTime = this.BackAnDisplayScroll.BackAnDisplayScrollTime; // Back Panel with time of the annotations in the scroll
|
||||
this.rsd = this.components.RangeSelectorDisplay = controlBar.BackAnDisplay.RangeSelectorDisplay; // Selection the time to display the annotations
|
||||
this.rsdl = this.components.RangeSelectorLeft = this.rsd.RangeSelectorLeft;
|
||||
this.rsdr = this.components.RangeSelectorRight = this.rsd.RangeSelectorRight;
|
||||
this.rsdb = this.components.RangeSelectorBar = this.rsd.RangeSelectorBar;
|
||||
this.rsdbl = this.components.RangeSelectorBarL = this.rsdb.RangeSelectorBarL;
|
||||
this.rsdbr = this.components.RangeSelectorBarR = this.rsdb.RangeSelectorBarR;
|
||||
this.rs = player.rangeslider;
|
||||
|
||||
// local variables
|
||||
this.editing = false;
|
||||
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = $.data(wrapper, 'annotator');
|
||||
var self = this;
|
||||
// Subscribe to Annotator changes
|
||||
annotator.subscribe("annotationsLoaded", function (annotations) {
|
||||
if(self.loaded)
|
||||
self.refreshDisplay();
|
||||
});
|
||||
annotator.subscribe("annotationUpdated", function (annotation) {
|
||||
if(self.loaded)
|
||||
self.refreshDisplay();
|
||||
});
|
||||
annotator.subscribe("annotationDeleted", function (annotation) {
|
||||
var annotations = annotator.plugins['Store'].annotations;
|
||||
var tot = typeof annotations !== 'undefined' ? annotations.length : 0;
|
||||
var attempts = 0; // max 100
|
||||
// This is to watch the annotations object, to see when is deleted the annotation
|
||||
var ischanged = function() {
|
||||
var new_tot = annotator.plugins['Store'].annotations.length;
|
||||
if (attempts < 100)
|
||||
setTimeout(function(){
|
||||
if (new_tot !== tot) {
|
||||
if(self.loaded)
|
||||
self.refreshDisplay();
|
||||
} else {
|
||||
attempts++;
|
||||
ischanged();
|
||||
}
|
||||
}, 100); // wait for the change in the annotations
|
||||
};
|
||||
ischanged();
|
||||
});
|
||||
|
||||
this.BigNewAn.hide(); // Hide until the video is load
|
||||
},
|
||||
newan: function(start, end) {
|
||||
var player = this.player;
|
||||
var annotator = this.annotator;
|
||||
var sumPercent = 10; // percentage for the last mark
|
||||
var currentTime = player.currentTime();
|
||||
var lastTime = this._sumPercent(currentTime, sumPercent);
|
||||
|
||||
var start = typeof start !== 'undefined' ? start : currentTime;
|
||||
var end = typeof end !== 'undefined' ? end : lastTime;
|
||||
|
||||
this._reset();
|
||||
|
||||
// set position RS and pause the player
|
||||
player.showSlider();
|
||||
player.pause();
|
||||
|
||||
player.setValueSlider(start, end);
|
||||
|
||||
// This variable is to say the editor that we want create a VideoJS annotation
|
||||
annotator.editor.VideoJS = this.player.id_;
|
||||
|
||||
annotator.adder.show();
|
||||
|
||||
this._setOverRS(annotator.adder);
|
||||
|
||||
// Open a new annotator dialog
|
||||
annotator.onAdderClick();
|
||||
},
|
||||
showDisplay: function() {
|
||||
this._reset();
|
||||
// show
|
||||
this.BackAnDisplay.removeClass('disable'); // show the Container
|
||||
this.BackAnDisplayScroll.removeClass('disable'); // show the scroll
|
||||
// active button
|
||||
this.ShowAn.addClass('active');
|
||||
this.options.showDisplay =true;
|
||||
},
|
||||
hideDisplay: function() {
|
||||
// hide
|
||||
this.BackAnDisplay.addClass('disable'); // hide the Container
|
||||
this.BackAnDisplayScroll.addClass('disable'); // hide the scroll
|
||||
// no active button
|
||||
videojs.removeClass(this.ShowAn.el_, 'active');
|
||||
this.options.showDisplay =false;
|
||||
},
|
||||
showStatistics: function() {
|
||||
this._reset();
|
||||
// show
|
||||
this.BackAnDisplay.removeClass('disable'); // show the Container
|
||||
this.AnStat.removeClass('disable'); // show Statistics
|
||||
// mode (this mode will hide the annotations to show the statistics in the container)
|
||||
this.BackAnDisplay.addClass('statistics'); // mode statistics
|
||||
// paint
|
||||
this.AnStat.paintCanvas(); // refresh canvas
|
||||
// active button
|
||||
this.ShowSt.addClass('active');
|
||||
this.options.showStatistics =true;
|
||||
},
|
||||
hideStatistics: function() {
|
||||
// hide
|
||||
this.BackAnDisplay.addClass('disable'); // hide the Container
|
||||
this.AnStat.addClass('disable'); // hide Statistics
|
||||
// remove mode statistics
|
||||
this.BackAnDisplay.removeClass('statistics');
|
||||
// no active button
|
||||
this.ShowSt.removeClass('active');
|
||||
this.options.showStatistics = false;
|
||||
},
|
||||
showAnnotation: function(annotation) {
|
||||
var isVideo = this._isVideoJS(annotation);
|
||||
if (isVideo) {
|
||||
var start = annotation.rangeTime.start;
|
||||
var end = annotation.rangeTime.end;
|
||||
var duration = this.player.duration();
|
||||
var isPoint = videojs.round(start, 3) == videojs.round(end, 3);
|
||||
|
||||
this._reset();
|
||||
|
||||
// show the range slider
|
||||
this.rs.show();
|
||||
|
||||
// set the slider position
|
||||
this.rs.setValues(start, end);
|
||||
|
||||
// lock the player
|
||||
this.rs.lock();
|
||||
|
||||
// play
|
||||
if (!isPoint)
|
||||
this.rs.playBetween(start, end);
|
||||
|
||||
// fix small bar
|
||||
var width = Math.min(1, Math.max(0.005, (this.rs._percent(end - start)))) * 100;
|
||||
this.rs.bar.el_.style.width = width + '%';
|
||||
|
||||
// Add the annotation object to the bar
|
||||
var bar = isPoint ? this.rs[((duration - start) / duration < 0.1) ? 'left' : 'right'].el_ : this.rs.bar.el_;
|
||||
var holder = $(this.rs.left.el_).parent()[0];
|
||||
$(holder).append('<span class="annotator-hl"></div>');
|
||||
$(bar).appendTo( $(holder).find('.annotator-hl'));
|
||||
|
||||
var span = $(bar).parent()[0];
|
||||
$.data(span, 'annotation', annotation); // Set the object in the span
|
||||
|
||||
// set the editor over the range slider
|
||||
this._setOverRS(this.annotator.editor.element);
|
||||
this.annotator.editor.checkOrientation();
|
||||
|
||||
// hide the panel
|
||||
this.rs.hidePanel();
|
||||
}
|
||||
},
|
||||
hideAnnotation: function() {
|
||||
this.rs.hide();
|
||||
this.rs.showPanel();
|
||||
|
||||
// remove the last single showed annotation
|
||||
var holder = $(this.rs.left.el_).parent()[0];
|
||||
var holderRight = $(this.rs.right.el_).parent()[0];
|
||||
if ($(holder).find('.annotator-hl').length > 0) {
|
||||
$($(holder).find('.annotator-hl')[0].children[0]).appendTo(holder);
|
||||
$(holder).find('.annotator-hl').remove();
|
||||
} else if ($(holderRight).find('.annotator-hl').length > 0) {
|
||||
$($(holderRight).find('.annotator-hl')[0].children[0]).appendTo(holderRight);
|
||||
$(holderRight).find('.annotator-hl').remove();
|
||||
}
|
||||
},
|
||||
editAnnotation: function(annotation, editor) {
|
||||
// This will be usefull when we are going to edit an annotation.
|
||||
if (this._isVideoJS(annotation)) {
|
||||
this.hideDisplay();
|
||||
var player = this.player;
|
||||
var editor = editor || this.annotator.editor;
|
||||
|
||||
// show the slider and set in the position
|
||||
player.showSlider();
|
||||
player.unlockSlider();
|
||||
player.setValueSlider(annotation.rangeTime.start, annotation.rangeTime.end);
|
||||
|
||||
// show the time panel
|
||||
player.showSliderPanel();
|
||||
|
||||
// set the editor over the range slider
|
||||
this._setOverRS(editor.element);
|
||||
editor.checkOrientation();
|
||||
|
||||
// set the VideoJS variable
|
||||
editor.VideoJS = player.id_;
|
||||
}
|
||||
},
|
||||
refreshDisplay: function() {
|
||||
var count = 0;
|
||||
var allannotations = this.annotator.plugins['Store'].annotations;
|
||||
|
||||
// Sort by date the Array
|
||||
this._sortByDate(allannotations);
|
||||
|
||||
// reset the panel
|
||||
$(this.AnDisplay.el_).find('span').remove(); // remove the last html items
|
||||
$(this.player.el_).find('.vjs-anpanel-annotation .annotation').remove(); // remove a deleted annotation without span wrapper
|
||||
|
||||
for (var item in allannotations) {
|
||||
var an = allannotations[item];
|
||||
|
||||
// check if the annotation is a video annotation
|
||||
if (this._isVideoJS(an)){
|
||||
var div = document.createElement('div');
|
||||
var span = document.createElement('span');
|
||||
var start = this.rs._percent(an.rangeTime.start) * 100;
|
||||
var end = this.rs._percent(an.rangeTime.end) * 100;
|
||||
var width;
|
||||
span.appendChild(div);
|
||||
span.className = "annotator-hl";
|
||||
width = Math.min(100, Math.max(0.2, end - start));
|
||||
div.className = "annotation";
|
||||
div.id = count;
|
||||
div.style.top = count + "em";
|
||||
div.style.left = start + '%';
|
||||
div.style.width = width + '%';
|
||||
div.start = an.rangeTime.start;
|
||||
div.end = an.rangeTime.end;
|
||||
this.AnDisplay.el_.appendChild(span);
|
||||
|
||||
// detect point annotations
|
||||
if (videojs.round(start, 0) == videojs.round(end, 0)) {
|
||||
$(div).css('width', '');
|
||||
$(div).addClass("point");
|
||||
}
|
||||
|
||||
// Set the object in the div
|
||||
$.data(span, 'annotation', an);
|
||||
// Add the highlights to the annotation
|
||||
an.highlights = $(span);
|
||||
|
||||
count++;
|
||||
}
|
||||
};
|
||||
var start = this.rs._seconds(parseFloat(this.rsdl.el_.style.left) / 100);
|
||||
var end = this.rs._seconds(parseFloat(this.rsdr.el_.style.left) / 100);
|
||||
|
||||
this.showBetween(start, end, this.rsdl.include, this.rsdr.include);
|
||||
},
|
||||
showBetween: function (start, end, includeLeft, includeRight) {
|
||||
var duration = this.player.duration();
|
||||
var start = start || 0;
|
||||
var end = end || duration;
|
||||
var annotationsHTML = $.makeArray($(this.player.el_).find('.vjs-anpanel-annotation .annotator-hl'));
|
||||
var count = 0;
|
||||
for (var index in annotationsHTML) {
|
||||
var an = $.data(annotationsHTML[index], 'annotation');
|
||||
var expressionLeft = includeLeft ? (an.rangeTime.end >= start) : (an.rangeTime.start >= start);
|
||||
var expressionRight = includeRight ? (an.rangeTime.start <= end) : (an.rangeTime.end <= end);
|
||||
if (this._isVideoJS(an) && expressionLeft && expressionRight && typeof an.highlights[0] !== 'undefined') {
|
||||
var annotationHTML = an.highlights[0].children[0];
|
||||
annotationHTML.style.marginTop = (-1 * parseFloat(annotationHTML.style.top) + count) + 'em';
|
||||
$(an.highlights[0]).show();
|
||||
count++;
|
||||
} else if (this._isVideoJS(an) && typeof an.highlights[0] !== 'undefined') {
|
||||
$(an.highlights[0]).hide();
|
||||
an.highlights[0].children[0].style.marginTop = '';
|
||||
}
|
||||
}
|
||||
// Set the times in the scroll time panel
|
||||
this.backDSTime.setTimes();
|
||||
},
|
||||
setposBigNew: function(pos) {
|
||||
var pos = pos || 'ul';
|
||||
var el = this.player.BigNewAnnotation.el_;
|
||||
videojs.removeClass(el, 'ul');
|
||||
videojs.removeClass(el, 'ur');
|
||||
videojs.removeClass(el, 'c');
|
||||
videojs.removeClass(el, 'bl');
|
||||
videojs.removeClass(el, 'br');
|
||||
videojs.addClass(el, pos);
|
||||
},
|
||||
pressedKey: function (key) {
|
||||
var player = this.player;
|
||||
var rs = this.player.rs;
|
||||
if (typeof key !== 'undefined' && key == 73) { // -- i key
|
||||
this._reset();
|
||||
|
||||
// show slider
|
||||
this.rs.show();
|
||||
// hide other elements
|
||||
this.rs._reset();
|
||||
this.rs.setValue(0, player.currentTime());
|
||||
this.rs.right.el_.style.visibility = 'hidden';
|
||||
this.rs.tpr.el_.style.visibility = 'hidden';
|
||||
this.rs.ctpr.el_.style.visibility = 'hidden';
|
||||
this.rs.bar.el_.style.visibility = 'hidden';
|
||||
this.lastStartbyKey = player.currentTime();
|
||||
} else if (typeof key!='undefined' && key==79) { // -- o key
|
||||
if (this.rs.bar.el_.style.visibility == 'hidden') { // the last action was to type the i key
|
||||
var start = this.lastStartbyKey != 'undefined' ? this.lastStartbyKey:0;
|
||||
this.newan(start, player.currentTime());
|
||||
} else {
|
||||
this.newan(player.currentTime(), player.currentTime());
|
||||
}
|
||||
}
|
||||
},
|
||||
refreshDesignPanel: function() {
|
||||
var player = this.player;
|
||||
var emtoPx = parseFloat($(this.backDSBar.el_).css('width'));
|
||||
var playerHeight = parseFloat($(player.el_).css('height'));
|
||||
var controlBarHeight = parseFloat($(player.controlBar.el_).css('height'));
|
||||
var newHeight = (playerHeight - controlBarHeight) / emtoPx - 5;
|
||||
this.BackAnDisplay.el_.style.height = this.backDSBar.el_.style.height = (newHeight + 'em');
|
||||
this.BackAnDisplay.el_.style.top = this.backDSBar.el_.style.top = "-" + (newHeight + 3 + 'em');
|
||||
this.BackAnDisplayScroll.el_.children[0].style.top = "-" + (newHeight + 5 + 'em');
|
||||
this.backDSTime.el_.children[0].style.top = "-" + (newHeight + 5 + 'em');
|
||||
},
|
||||
_reset: function() {
|
||||
// Hide all the components
|
||||
this.hideDisplay();
|
||||
this.hideAnnotation();
|
||||
this.hideStatistics();
|
||||
this.player.annotator.adder.hide();
|
||||
this.player.annotator.editor.hide();
|
||||
this.player.annotator.viewer.hide();
|
||||
|
||||
// make visible all the range slider element that maybe were hidden in pressedKey event
|
||||
this.rs.right.el_.style.visibility = '';
|
||||
this.rs.tpr.el_.style.visibility = '';
|
||||
this.rs.ctpr.el_.style.visibility = '';
|
||||
this.rs.bar.el_.style.visibility = '';
|
||||
|
||||
// by default the range slider must be unlocked
|
||||
this.rs.unlock();
|
||||
|
||||
// whether there is a playing selection
|
||||
this.rs.bar.suspendPlay();
|
||||
|
||||
// refresh the design
|
||||
this.refreshDesignPanel();
|
||||
},
|
||||
_setOverRS: function(elem) {
|
||||
var annotator = this.player.annotator;
|
||||
var wrapper = $('.annotator-wrapper')[0];
|
||||
var positionLeft = videojs.findPosition(this.rs.left.el_);
|
||||
var positionRight = videojs.findPosition(this.rs.right.el_);
|
||||
var positionAnnotator = videojs.findPosition(wrapper);
|
||||
var positionAdder = {};
|
||||
|
||||
elem[0].style.display = 'block'; // Show the adder
|
||||
|
||||
if (this.player.isFullScreen) {
|
||||
positionAdder.top = positionLeft.top;
|
||||
positionAdder.left = positionLeft.left + (positionRight.left - positionLeft.left) / 2;
|
||||
} else {
|
||||
positionAdder.left = positionLeft.left + (positionRight.left - positionLeft.left) / 2 - positionAnnotator.left;
|
||||
positionAdder.top = positionLeft.top - positionAnnotator.top;
|
||||
}
|
||||
|
||||
elem.css(positionAdder);
|
||||
},
|
||||
_onMouseDownRS: function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!this.rs.options.locked) {
|
||||
videojs.on(document, "mousemove", videojs.bind(this, this._onMouseMoveRS));
|
||||
videojs.on(document, "mouseup", videojs.bind(this, this._onMouseUpRS));
|
||||
}
|
||||
},
|
||||
_onMouseMoveRS: function(event) {
|
||||
var player = this.player;
|
||||
var annotator = player.annotator;
|
||||
var rs = player.rangeslider;
|
||||
annotator.editor.element[0].style.display = 'none';
|
||||
rs.show();
|
||||
this._setOverRS(annotator.adder);
|
||||
},
|
||||
_onMouseUpRS: function(event) {
|
||||
videojs.off(document, "mousemove", this._onMouseMoveRS, false);
|
||||
videojs.off(document, "mouseup", this._onMouseUpRS, false);
|
||||
|
||||
var player = this.player;
|
||||
var annotator = player.annotator;
|
||||
var rs = player.rangeslider;
|
||||
annotator.editor.element[0].style.display = 'block';
|
||||
|
||||
this._setOverRS(annotator.editor.element);
|
||||
},
|
||||
_sumPercent: function(seconds, percent) {
|
||||
// the percentage is in %
|
||||
var duration = this.player.duration();
|
||||
var seconds = seconds || 0;
|
||||
var percent = percent || 10;
|
||||
percent = Math.min(100, Math.max(0, percent));
|
||||
|
||||
if (isNaN(duration)) {
|
||||
return 0;
|
||||
}
|
||||
return Math.min(duration, Math.max(0, seconds + duration * percent / 100));
|
||||
},
|
||||
// Detect if we are creating or editing a video-js annotation
|
||||
_EditVideoAn: function () {
|
||||
var annotator = this.annotator;
|
||||
var isOpenVideojs = (typeof this.player != 'undefined');
|
||||
var VideoJS = annotator.editor.VideoJS;
|
||||
return (isOpenVideojs && typeof VideoJS!='undefined' && VideoJS!==-1);
|
||||
},
|
||||
// Detect if the annotation is a video-js annotation
|
||||
_isVideoJS: function (an) {
|
||||
var player = this.player;
|
||||
var rt = an.rangeTime;
|
||||
var isOpenVideojs = (typeof this.player !== 'undefined');
|
||||
var isVideo = (typeof an.media !== 'undefined' && (an.media === 'video' || an.media === 'audio'));
|
||||
var isContainer = (typeof an.target !== 'undefined' && an.target.container == player.id_ );
|
||||
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
|
||||
var isSource = false;
|
||||
if (isContainer) {
|
||||
// Compare without extension
|
||||
var isYoutube = (isOpenVideojs && typeof this.player.techName !== 'undefined') ? (this.player.techName === 'Youtube') : false;
|
||||
var targetSrc = isYoutube ? an.target.src : an.target.src.substring(0, an.target.src.lastIndexOf("."));
|
||||
var playerSrc = isYoutube ? player.options_.sources[0].src : player.options_.sources[0].src.substring(0, player.options_.sources[0].src.lastIndexOf("."));
|
||||
isSource = (targetSrc === playerSrc);
|
||||
}
|
||||
return (isOpenVideojs && isVideo && isContainer && isSource && isNumber);
|
||||
},
|
||||
_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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------CREATE new Components for video-js---------------- //
|
||||
|
||||
// --Charge the new Component into videojs
|
||||
videojs.ControlBar.prototype.options_.children.AnContainerButtons = {}; // Container with the css for the buttons
|
||||
videojs.ControlBar.prototype.options_.children.BackAnDisplay = {}; // Range Slider Time Bar
|
||||
videojs.ControlBar.prototype.options_.children.BackAnDisplayScroll = {}; // Range Slider Time Bar
|
||||
videojs.options.children.BigNewAnnotation = {}; // Big Button New Annotation
|
||||
|
||||
|
||||
|
||||
// -- Player--> BigNewAnnotation
|
||||
|
||||
/**
|
||||
* Create a New Annotation with big Button
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.BigNewAnnotation = videojs.Button.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Button.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.BigNewAnnotation.prototype.init_ = function() {
|
||||
this.an = this.player_.annotations;
|
||||
// Hide Button if the user has selected readOnly in the Annotator options
|
||||
var opts = this.an.options.optionsAnnotator;
|
||||
if (typeof opts !== 'undefined' && typeof opts.readOnly !== 'undefined' && opts.readOnly)
|
||||
this.hide();
|
||||
};
|
||||
|
||||
videojs.BigNewAnnotation.prototype.createEl = function() {
|
||||
return videojs.Button.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-big-new-annotation vjs-menu-button vjs-control',
|
||||
innerHTML: '<div class="vjs-big-menu-button vjs-control">A</div>',
|
||||
title: 'New Annotation',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.BigNewAnnotation.prototype.onClick = function() {
|
||||
this.an.newan();
|
||||
};
|
||||
|
||||
// -- Player--> ControlBar--> AnContainerButtons
|
||||
|
||||
/**
|
||||
* Container for the button CSS
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.AnContainerButtons = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.AnContainerButtons.prototype.init_ = function() {};
|
||||
|
||||
|
||||
videojs.AnContainerButtons.prototype.options_ = {
|
||||
children: {
|
||||
'ShowStatistics': {},
|
||||
'ShowAnnotations': {},
|
||||
'NewAnnotation': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.AnContainerButtons.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-container-button-annotation vjs-menu-button vjs-control',
|
||||
});
|
||||
};
|
||||
|
||||
// -- Player--> ControlBar--> AnContainerButtons--> ShowStatistics
|
||||
|
||||
/**
|
||||
* Button for show/hide the chart with statistics of the annotation's number
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.ShowStatistics = videojs.Button.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Button.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.ShowStatistics.prototype.init_ = function() {
|
||||
this.an = this.player_.annotations;
|
||||
};
|
||||
|
||||
videojs.ShowStatistics.prototype.createEl = function() {
|
||||
return videojs.Button.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-statistics-annotation vjs-menu-button vjs-control',
|
||||
title: 'Show the Statistics',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.ShowStatistics.prototype.onClick = function() {
|
||||
if (!this.an.options.showStatistics) this.an.showStatistics();
|
||||
else this.an.hideStatistics();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> AnContainerButtons--> ShowAnnotations
|
||||
|
||||
/**
|
||||
* Button for show/hide the annotation panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.ShowAnnotations = videojs.Button.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Button.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.ShowAnnotations.prototype.init_ = function() {
|
||||
this.an = this.player_.annotations;
|
||||
};
|
||||
|
||||
videojs.ShowAnnotations.prototype.createEl = function() {
|
||||
return videojs.Button.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-showannotations-annotation vjs-menu-button vjs-control',
|
||||
title: 'Show Annotations',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.ShowAnnotations.prototype.onClick = function() {
|
||||
if (!this.an.options.showDisplay) this.an.showDisplay();
|
||||
else this.an.hideDisplay();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> AnContainerButtons--> NewAnnotation
|
||||
|
||||
/**
|
||||
* Create a New Annotation
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.NewAnnotation = videojs.Button.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Button.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.NewAnnotation.prototype.init_ = function() {
|
||||
this.an = this.player_.annotations;
|
||||
// Hide Button if the user has selected readOnly in the Annotator options
|
||||
var opts = this.an.options.optionsAnnotator;
|
||||
if (typeof opts !== 'undefined' && typeof opts.readOnly !== 'undefined' && opts.readOnly)
|
||||
this.hide();
|
||||
};
|
||||
|
||||
videojs.NewAnnotation.prototype.createEl = function() {
|
||||
return videojs.Button.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-new-annotation vjs-menu-button vjs-control',
|
||||
title: 'New Annotation',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.NewAnnotation.prototype.onClick = function() {
|
||||
this.an.newan();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay
|
||||
|
||||
/**
|
||||
* The background annotations panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.BackAnDisplay = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.BackAnDisplay.prototype.init_ = function() {
|
||||
this.an = this.player_.annotations
|
||||
self = this;
|
||||
// Fix error resizing the display panel. The scroll always went up.
|
||||
$(this.el_).watch('font-size', function() {
|
||||
self.an.backDSBarSel.setPosition(self.an.BackAnDisplayScroll.currentValue, false);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
videojs.BackAnDisplay.prototype.options_ = {
|
||||
children: {
|
||||
'RangeSelectorDisplay': {},
|
||||
'AnDisplay': {},
|
||||
'AnStat': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.BackAnDisplay.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-back-anpanel-annotation',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay
|
||||
|
||||
/**
|
||||
* The selector to show the annotations in a time selection
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.RangeSelectorDisplay = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
var duration = this.an.player.duration();
|
||||
this.start = 0;
|
||||
this.end = duration;
|
||||
|
||||
// set the selection area in the extreme position
|
||||
this.setPosition(0, 0, false);
|
||||
this.setPosition(1, this.rs._percent(duration), false);
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.options_ = {
|
||||
children: {
|
||||
'RangeSelectorLeft': {},
|
||||
'RangeSelectorRight': {},
|
||||
'RangeSelectorBar': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-rangeselector-anpanel-annotation',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.onMouseDown = function(event) {
|
||||
event.preventDefault();
|
||||
// videojs.blockTextSelection();
|
||||
|
||||
videojs.on(document, "mousemove", videojs.bind(this, this.onMouseMove));
|
||||
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
|
||||
|
||||
videojs.removeClass(this.an.rsdb.el_, 'disable');
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mousemove", this.onMouseMove, false);
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
|
||||
videojs.addClass(this.an.rsdb.el_, 'disable');
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.onMouseMove = function(event) {
|
||||
var left = this.calculateDistance(event);
|
||||
if (this.an.rsdl.pressed)
|
||||
this.setPosition(0, left);
|
||||
else if (this.an.rsdr.pressed)
|
||||
this.setPosition(1, left);
|
||||
|
||||
// move the frame to the position of the arrow
|
||||
this.an.player.currentTime(this.rs._seconds(left));
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.calculateDistance = function(event) {
|
||||
var rstbX = this.getRSTBX();
|
||||
var rstbW = this.getRSTBWidth();
|
||||
var handleW = this.getWidth();
|
||||
|
||||
// Adjusted X and Width, so handle doesn't go outside the bar
|
||||
rstbX = rstbX + (handleW / 2);
|
||||
rstbW = rstbW - handleW;
|
||||
|
||||
// Percent that the click is through the adjusted area
|
||||
return Math.max(0, Math.min(1, (event.pageX - rstbX) / rstbW));
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.getRSTBWidth = function() {
|
||||
return this.el_.offsetWidth;
|
||||
};
|
||||
videojs.RangeSelectorDisplay.prototype.getRSTBX = function() {
|
||||
return videojs.findPosition(this.el_).left;
|
||||
};
|
||||
videojs.RangeSelectorDisplay.prototype.getWidth = function() {
|
||||
var arrow = $(this.an.rsdl.el_).find('.vjs-selector-arrow')[0];
|
||||
return arrow.offsetWidth; // does not matter left or right
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.setPosition = function(index, left, changeTime) {
|
||||
// index = 0 for left side, index = 1 for right side
|
||||
var index = index || 0;
|
||||
var changeTime = typeof changeTime !== 'undefined' ? changeTime : true;
|
||||
|
||||
// Check for invalid position
|
||||
if(isNaN(left))
|
||||
return false;
|
||||
|
||||
// Check index between 0 and 1
|
||||
if (!(index === 0 || index === 1))
|
||||
return false;
|
||||
// Alias
|
||||
var ObjLeft = this.an.rsdl.el_;
|
||||
var ObjRight = this.an.rsdr.el_;
|
||||
var Obj = this.an[index === 0 ? 'rsdl' : 'rsdr'].el_;
|
||||
|
||||
// Check if left arrow is over the right arrow
|
||||
if ((index === 0 ? this.updateLeft(left) : this.updateRight(left))) {
|
||||
if (index === 1) { // right
|
||||
Obj.style.left = (left * 100) + '%';
|
||||
Obj.style.width = ((1 - left) * 100) + '%';
|
||||
} else { // left
|
||||
Obj.style.left = (left * 100) + '%';
|
||||
Obj.style.width = ((left) * 100) + '%';
|
||||
}
|
||||
|
||||
this[index === 0 ? 'start' : 'end'] = this.rs._seconds(left);
|
||||
|
||||
// Fix the problem when you press the button and the two arrow are underhand
|
||||
// left.zIndex = 10 and right.zIndex=20. This is always less in this case:
|
||||
if (index === 0 && (left * 100) >= 90)
|
||||
$(ObjLeft).find('.vjs-selector-arrow')[0].style.zIndex = 25;
|
||||
else
|
||||
$(ObjLeft).find('.vjs-selector-arrow')[0].style.zIndex = 10;
|
||||
|
||||
|
||||
// -- Panel
|
||||
var rsdbl = this.an.rsdbl.el_,
|
||||
rsdbr = this.an.rsdbr.el_,
|
||||
distance = parseFloat(ObjRight.style.left) - parseFloat(ObjLeft.style.left);
|
||||
if (index === 0)
|
||||
rsdbl.children[0].innerHTML = videojs.formatTime(this.rs._seconds(left));
|
||||
else
|
||||
rsdbr.children[0].innerHTML = videojs.formatTime(this.rs._seconds(left));
|
||||
if (typeof distance !== 'undefined' && distance <= 12.5) {
|
||||
if (parseFloat(ObjLeft.style.left) < 7) {
|
||||
rsdbl.style.top = (-1.5) + 'em';
|
||||
rsdbl.style.left = 1 + 'em';
|
||||
} else {
|
||||
rsdbl.style.left = (-2.5) + 'em';
|
||||
rsdbl.style.top = '';
|
||||
}
|
||||
|
||||
if (parseFloat(ObjRight.style.left) > 93) {
|
||||
rsdbr.style.top = (-1.5) + 'em';
|
||||
rsdbr.style.right = 1 + 'em';
|
||||
} else {
|
||||
rsdbr.style.right = (-2.5) + 'em';
|
||||
rsdbr.style.top = '';
|
||||
}
|
||||
} else {
|
||||
rsdbl.style.left = 1 + 'em';
|
||||
rsdbr.style.right = 1 + 'em';
|
||||
rsdbl.style.top = '';
|
||||
rsdbr.style.top = '';
|
||||
}
|
||||
|
||||
|
||||
var start = this.rs._seconds(parseFloat(ObjLeft.style.left) / 100);
|
||||
var end = this.rs._seconds(parseFloat(ObjRight.style.left) / 100);
|
||||
|
||||
if (changeTime)
|
||||
this.an.showBetween(start, end, this.an.rsdl.include, this.an.rsdr.include);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.updateLeft = function(left) {
|
||||
var rightVal = this.an.rsdr.el_.style.left !== '' ? this.an.rsdr.el_.style.left : 100;
|
||||
var right = parseFloat(rightVal) / 100;
|
||||
var bar = this.an.rsdb.el_;
|
||||
|
||||
var width = videojs.round((right - left), this.an.updatePrecision); // round necessary for not get 0.6e-7 for example that it's not able for the html css width
|
||||
if(left <= (right+0.00001)) {
|
||||
bar.style.left = (left * 100) + '%';
|
||||
bar.style.width = (width * 100) + '%';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
videojs.RangeSelectorDisplay.prototype.updateRight = function(right) {
|
||||
var leftVal = this.an.rsdl.el_.style.left !== '' ? this.an.rsdl.el_.style.left : 0;
|
||||
var left = parseFloat(leftVal) / 100;
|
||||
var bar = this.an.rsdb.el_;
|
||||
|
||||
var width = videojs.round((right - left), this.an.updatePrecision); // round necessary for not get 0.6e-7 for example that it's not able for the html css width
|
||||
|
||||
if((right+0.00001) >= left) {
|
||||
bar.style.width = (width * 100) + '%';
|
||||
bar.style.left = ((right - width) * 100) + '%';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorLeft
|
||||
|
||||
/**
|
||||
* Left Time selector
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.RangeSelectorLeft = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
this.on('dblclick', this.ondblclick);
|
||||
this.pressed = false; // to know when is mousedown
|
||||
this.include = true; // to know when we want to include the boundary time in the selection or not
|
||||
}
|
||||
});
|
||||
|
||||
videojs.RangeSelectorLeft.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
videojs.addClass(this.el_, 'include');
|
||||
};
|
||||
|
||||
videojs.RangeSelectorLeft.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-leftselector-anpanel-annotation',
|
||||
innerHTML: '<div class="vjs-selector-arrow" title="Left Annotation Selector"></div><div class="vjs-leftselector-back"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
videojs.RangeSelectorLeft.prototype.onMouseDown = function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.pressed = true;
|
||||
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
|
||||
videojs.addClass(this.el_, 'active');
|
||||
videojs.addClass(this.el_.parentNode, 'active');
|
||||
};
|
||||
|
||||
videojs.RangeSelectorLeft.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
videojs.removeClass(this.el_, 'active');
|
||||
videojs.removeClass(this.el_.parentNode, 'active');
|
||||
this.pressed = false;
|
||||
};
|
||||
|
||||
videojs.RangeSelectorLeft.prototype.ondblclick = function(event) {
|
||||
if (this.include) {
|
||||
this.include = false;
|
||||
videojs.removeClass(this.el_, 'include');
|
||||
} else {
|
||||
this.include = true;
|
||||
videojs.addClass(this.el_, 'include');
|
||||
}
|
||||
var left = this.an.rsd.calculateDistance(event);
|
||||
this.an.rsd.setPosition(0, left);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorRight
|
||||
|
||||
/**
|
||||
* Right Time selector
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.RangeSelectorRight = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
this.on('dblclick', this.ondblclick);
|
||||
this.pressed = false; // to know when is mousedown
|
||||
this.include = true; // to know when we want to include the boundary time in the selection or not
|
||||
}
|
||||
});
|
||||
|
||||
videojs.RangeSelectorRight.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
videojs.addClass(this.el_, 'include');
|
||||
};
|
||||
|
||||
videojs.RangeSelectorRight.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-rightselector-anpanel-annotation',
|
||||
innerHTML: '<div class="vjs-selector-arrow" title="Right Annotation Selector"></div><div class="vjs-rightselector-back"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
videojs.RangeSelectorRight.prototype.onMouseDown = function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.pressed = true;
|
||||
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
|
||||
videojs.addClass(this.el_, 'active');
|
||||
videojs.addClass(this.el_.parentNode, 'active');
|
||||
};
|
||||
|
||||
videojs.RangeSelectorRight.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
videojs.removeClass(this.el_, 'active');
|
||||
videojs.removeClass(this.el_.parentNode, 'active');
|
||||
this.pressed = false;
|
||||
};
|
||||
|
||||
videojs.RangeSelectorRight.prototype.ondblclick = function(event) {
|
||||
if (this.include){
|
||||
this.include = false;
|
||||
videojs.removeClass(this.el_, 'include');
|
||||
}else{
|
||||
this.include = true;
|
||||
videojs.addClass(this.el_, 'include');
|
||||
}
|
||||
var left = this.an.rsd.calculateDistance(event);
|
||||
this.an.rsd.setPosition(1, left);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar
|
||||
|
||||
/**
|
||||
* Bar to display the selected Time
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.RangeSelectorBar = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.RangeSelectorBar.prototype.init_ = function() {
|
||||
videojs.addClass(this.el_, 'disable');
|
||||
};
|
||||
|
||||
videojs.RangeSelectorBar.prototype.options_ = {
|
||||
children: {
|
||||
'RangeSelectorBarL': {},
|
||||
'RangeSelectorBarR': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.RangeSelectorBar.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-barselector-anpanel-annotation',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar--> RangeSelectorBarL
|
||||
|
||||
/**
|
||||
* This is the left time panel for RangeSelectorBar
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.RangeSelectorBarL = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.RangeSelectorBarL.prototype.init_ = function() {};
|
||||
|
||||
videojs.RangeSelectorBarL.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-barselector-left',
|
||||
innerHTML: '<span class="vjs-time-text">00:00</span>',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> RangeSelectorDisplay--> RangeSelectorBar--> RangeSelectorBarR
|
||||
/**
|
||||
* This is the right time panel for RangeSelectorBar
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.RangeSelectorBarR = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.RangeSelectorBarR.prototype.init_ = function() {};
|
||||
|
||||
videojs.RangeSelectorBarR.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-barselector-right',
|
||||
innerHTML: '<span class="vjs-time-text">00:00</span>'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> AnDisplay
|
||||
|
||||
/**
|
||||
* Show the annotations in a panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.AnDisplay = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
this.on('mouseover', this.onMouseOver);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.AnDisplay.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
this.transition = false;
|
||||
};
|
||||
|
||||
videojs.AnDisplay.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-anpanel-annotation',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.AnDisplay.prototype.onMouseDown = function(event) {
|
||||
var elem = $(event.target).parents('.annotator-hl').andSelf();
|
||||
var _self = this;
|
||||
if (elem.hasClass("annotator-hl")) {
|
||||
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
|
||||
// Clone the bar box to make the animation
|
||||
var boxup = document.createElement('div');
|
||||
var ElemTop = parseFloat(elem[1].style.top);
|
||||
var ElemMargin = parseFloat(elem[1].style.marginTop);
|
||||
var emtoPx = parseFloat($(elem[1]).css('height'));
|
||||
var isPoint = $(elem[1]).hasClass("point");
|
||||
|
||||
boxup.className = isPoint ? "boxup-dashed-line point" : "boxup-dashed-line";
|
||||
boxup.style.left = elem[1].style.left;
|
||||
boxup.style.width = elem[1].style.width;
|
||||
|
||||
boxup.style.top = (ElemTop + ElemMargin - this.el_.scrollTop / emtoPx) + 'em';
|
||||
elem[0].parentNode.parentNode.appendChild(boxup);
|
||||
}
|
||||
}
|
||||
|
||||
videojs.AnDisplay.prototype.onMouseUp = function(event) {
|
||||
if (typeof this.lastelem === 'undefined')
|
||||
return false;
|
||||
var elem = this.lastelem;
|
||||
var _self = this;
|
||||
if (elem.hasClass("annotator-hl")) {
|
||||
var annotation = elem.map(function() {
|
||||
return $(this).data("annotation");
|
||||
})[0];
|
||||
var displayHeight = (-1) * parseFloat($(this.el_).parent()[0].style.top);
|
||||
var emtoPx = parseFloat($(elem[1]).css('height'));
|
||||
if (typeof $(elem).parent().parent().find('.boxup-dashed-line')[0] !== 'undefined') {
|
||||
$(elem).parent().parent().find('.boxup-dashed-line')[0].style.top = (displayHeight - 2) + 'em';
|
||||
}
|
||||
|
||||
this.an.player.pause();
|
||||
this.transition = true;
|
||||
window.setTimeout(function () {
|
||||
_self.an.showAnnotation(annotation);
|
||||
_self.transition = false;
|
||||
_self.onCloseViewer();
|
||||
}, 900);
|
||||
}
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
};
|
||||
|
||||
videojs.AnDisplay.prototype.onMouseOver = function(event) {
|
||||
if (!this.transition && !this.an.rsdl.pressed && !this.an.rsdr.pressed) {
|
||||
var annotator = this.an.annotator;
|
||||
var elem = $(event.target).parents('.annotator-hl').andSelf();
|
||||
|
||||
// if there is a opened annotation then show the new annotation mouse over
|
||||
if (typeof annotator !== 'undefined' && annotator.viewer.isShown() && elem.hasClass("annotator-hl")) {
|
||||
// hide the last open viewer
|
||||
annotator.viewer.hide();
|
||||
// get the annotation over the mouse
|
||||
var annotations = elem.map(function() {
|
||||
return $(this).data("annotation");
|
||||
});
|
||||
// show the annotation in the viewer
|
||||
annotator.showViewer($.makeArray(annotations), Util.mousePosition(event, annotator.wrapper[0]));
|
||||
}
|
||||
|
||||
// create dashed line
|
||||
elem.addClass('active');
|
||||
if (typeof elem !== 'undefined' && $(elem[1]).hasClass('annotation')) {
|
||||
// create dashed line under the bar
|
||||
var dashed = document.createElement('div');
|
||||
var boxdown = document.createElement('div');
|
||||
var DisplayHeight = parseFloat(this.an.BackAnDisplay.el_.style.height);
|
||||
var ElemMarginTop = elem[1].style.marginTop !== '' ? parseFloat(elem[1].style.marginTop) : 0;
|
||||
var ElemTop = parseFloat(elem[1].style.top) + ElemMarginTop;
|
||||
var emtoPx = parseFloat($(elem[1]).css('height'));
|
||||
var isPoint = $(elem[1]).hasClass("point");
|
||||
|
||||
dashed.className = isPoint ? 'dashed-line point' : 'dashed-line';
|
||||
boxdown.className = "box-dashed-line";
|
||||
dashed.style.left = boxdown.style.left = elem[1].style.left;
|
||||
dashed.style.width = boxdown.style.width = isPoint ? '0' : elem[1].style.width;
|
||||
dashed.style.top = ((ElemTop + 1) - this.el_.scrollTop / emtoPx) + 'em';
|
||||
dashed.style.height = ((DisplayHeight - ElemTop + 2) + this.el_.scrollTop / emtoPx) + 'em'; // get the absolute value of the top to put in the height
|
||||
boxdown.style.top = (DisplayHeight + 2) + 'em';
|
||||
elem[0].parentNode.parentNode.appendChild(dashed);
|
||||
elem[0].parentNode.parentNode.appendChild(boxdown);
|
||||
|
||||
$(this.player).find('.vjs-play-progress').css('z-index', 2);
|
||||
$(this.player).find('.vjs-seek-handle').css('z-index', 2);
|
||||
}
|
||||
|
||||
// store the last selected item
|
||||
if (elem.hasClass("annotator-hl"))
|
||||
this.lastelem = elem;
|
||||
}
|
||||
};
|
||||
|
||||
videojs.AnDisplay.prototype.onCloseViewer = function() {
|
||||
if (!this.transition) {
|
||||
if (typeof this.lastelem !== 'undefined')
|
||||
this.lastelem.removeClass('active');
|
||||
// remove dashed line
|
||||
if (typeof this.lastelem !== 'undefined' && this.lastelem.hasClass("annotator-hl")) {
|
||||
$(this.lastelem).parent().parent().find('.dashed-line').remove();
|
||||
$(this.lastelem).parent().parent().find('.box-dashed-line').remove();
|
||||
$(this.lastelem).parent().parent().find('.boxup-dashed-line').remove();
|
||||
$(this.player).find('.vjs-play-progress').css('z-index', "");
|
||||
$(this.player).find('.vjs-seek-handle').css('z-index', "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
videojs.AnDisplay.prototype.countVisibles = function() {
|
||||
var AnArray = $.makeArray(this.el_.children);
|
||||
// Count visible annotations in Panel
|
||||
var count = 0;
|
||||
for (var index in AnArray) {
|
||||
var an = AnArray[index];
|
||||
if (an.style.display !== 'none') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplay--> AnStat
|
||||
|
||||
/**
|
||||
* Display with a chart with the statistics of the number of Annotations
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.AnStat = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
this.marginTop = 20;
|
||||
this.marginBottom = 0;
|
||||
}
|
||||
});
|
||||
|
||||
videojs.AnStat.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
this.canvas = this.el_.children[0];
|
||||
};
|
||||
|
||||
videojs.AnStat.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-anstat-annotation',
|
||||
innerHTML: '<canvas class="vjs-char-anstat-annotation">Your browser does not support the HTML5 canvas tag.</canvas>',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.AnStat.prototype.paintCanvas = function() {
|
||||
var ctx = this.canvas.getContext("2d");
|
||||
var points = this._getPoints();
|
||||
var w = this._getWeights(points);
|
||||
var maxEn = this._getMaxArray(points, 'entries');
|
||||
var TotAn = this.an.AnDisplay.el_.children.length;
|
||||
var duration = this.an.player.duration();
|
||||
|
||||
// set the position of the canvas
|
||||
this.canvas.style.marginTop = Math.round(this.marginTop) + 'px';
|
||||
|
||||
// Add the Max Concentration and Number of annotations
|
||||
if($(this.canvas).parent().find('.vjs-totan-anstat-annotation').length === 0) {
|
||||
$(this.canvas).parent().append('<div class="vjs-totan-anstat-annotation">');
|
||||
$(this.canvas).parent().append('<div class="vjs-maxcon-anstat-annotation">');
|
||||
}
|
||||
var textCanvas = $(this.canvas).parent().find('.vjs-totan-anstat-annotation')[0];
|
||||
textCanvas.innerHTML = TotAn + ' total annotations';
|
||||
var textCanvas = $(this.canvas).parent().find('.vjs-maxcon-anstat-annotation')[0];
|
||||
textCanvas.innerHTML = 'Max Annotations = ' + maxEn;
|
||||
|
||||
// Added dashed line function to paint
|
||||
if (window.CanvasRenderingContext2D && CanvasRenderingContext2D.prototype.lineTo) {
|
||||
CanvasRenderingContext2D.prototype.dashedLine = function(x1, y1, x2, y2, dashLen) {
|
||||
if (dashLen === undefined) dashLen = 2;
|
||||
|
||||
this.beginPath();
|
||||
this.moveTo(x1, y1);
|
||||
|
||||
var dX = x2 - x1;
|
||||
var dY = y2 - y1;
|
||||
var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
|
||||
var dashX = dX / dashes;
|
||||
var dashY = dY / dashes;
|
||||
|
||||
var q = 0;
|
||||
while (q++ < dashes) {
|
||||
x1 += dashX;
|
||||
y1 += dashY;
|
||||
this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x1, y1);
|
||||
}
|
||||
this[q % 2 == 0 ? 'moveTo' : 'lineTo'](x2, y2);
|
||||
|
||||
this.stroke();
|
||||
this.closePath();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// set the canvas size
|
||||
this.canvas.height = this.an.AnDisplay.el_.offsetHeight - (this.marginTop + this.marginBottom);
|
||||
this.canvas.width = this.an.AnDisplay.el_.offsetWidth;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = "rgb(255, 163, 0)";
|
||||
var lastSe = 0;
|
||||
var lastEn = 0;
|
||||
ctx.moveTo(0, maxEn * w.Y); // Move pointer to 0, 0
|
||||
for (var index in points) {
|
||||
var p = points[index];
|
||||
var x1 = lastSe * w.X, y1 = (maxEn - lastEn) * w.Y; // Old Point
|
||||
var x2 = p.second * w.X, y2 = (maxEn - p.entries) * w.Y; // New Point
|
||||
// new line
|
||||
ctx.lineTo(x2, y1); // move horizontally to the new point
|
||||
ctx.moveTo(x2, y1); // Move pointer
|
||||
ctx.lineTo(x2, y2); // move vertically to the new point height
|
||||
ctx.moveTo(x2, y2); // Prepare pointer for a new instance
|
||||
// new rectangle under the curve
|
||||
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
|
||||
ctx.fillRect(x1, y1, (x2 - x1), (maxEn * w.Y - y1));
|
||||
|
||||
// store the last point
|
||||
lastSe = p.second;
|
||||
lastEn = p.entries;
|
||||
}
|
||||
// set the graphic to the end of the video
|
||||
ctx.lineTo(lastSe * w.X, maxEn * w.Y);
|
||||
ctx.moveTo(lastSe * w.X, maxEn * w.Y);
|
||||
ctx.lineTo(duration * w.X, maxEn * w.Y);
|
||||
ctx.stroke();
|
||||
|
||||
// dashed line down
|
||||
ctx.beginPath();
|
||||
ctx.dashedLine(0, maxEn * w.Y, duration * w.X, maxEn * w.Y, 8);
|
||||
ctx.stroke();
|
||||
// dashed line top
|
||||
ctx.beginPath();
|
||||
ctx.dashedLine(0, 0, duration * w.X, 0, 8);
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
videojs.AnStat.prototype._getWeights = function(points){
|
||||
var weight = {};
|
||||
var panel = $(this.an.AnDisplay.el_);
|
||||
var maxSe = this.an.player.duration();
|
||||
var maxEn = this._getMaxArray(points, 'entries');
|
||||
var panelW = parseFloat(panel.css('width'));
|
||||
var panelH = parseFloat(panel.css('height')) - (this.marginTop + this.marginBottom);
|
||||
weight.X = maxSe != 0 ? (panelW / maxSe) : 0;
|
||||
weight.Y = maxEn != 0 ? (panelH / maxEn) : 0;
|
||||
return weight;
|
||||
};
|
||||
|
||||
videojs.AnStat.prototype._getMaxArray = function(points, variable) {
|
||||
var highest = 0;
|
||||
var tmp;
|
||||
for (var index in points) {
|
||||
tmp = points[index][variable];
|
||||
if (tmp > highest) highest = tmp;
|
||||
}
|
||||
return highest;
|
||||
};
|
||||
|
||||
videojs.AnStat.prototype._getPoints = function() {
|
||||
var points = [];
|
||||
var allannotations = this.an.annotator.plugins.Store.annotations;
|
||||
for (var index in allannotations) {
|
||||
var an = allannotations[index];
|
||||
var start, end;
|
||||
if (this.an._isVideoJS(an)) {
|
||||
start = an.rangeTime.start;
|
||||
end = an.rangeTime.end;
|
||||
// start
|
||||
if (!this._isFound(points, start)) {
|
||||
points.push({
|
||||
second:an.rangeTime.start,
|
||||
entries:this._getNumberAnnotations(start)
|
||||
});
|
||||
if (an.rangeTime.start == an.rangeTime.end){ // is a point
|
||||
points.push({
|
||||
second:an.rangeTime.end,
|
||||
entries:this._getNumberAnnotations(end, true)
|
||||
});
|
||||
}
|
||||
}
|
||||
// end
|
||||
if (!this._isFound(points, end)) {
|
||||
points.push({
|
||||
second:an.rangeTime.end,
|
||||
entries:this._getNumberAnnotations(end, true)
|
||||
});
|
||||
}
|
||||
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
points.sort(function(a, b) {
|
||||
return parseFloat(a.second) - parseFloat(b.second)
|
||||
});
|
||||
return points;
|
||||
};
|
||||
|
||||
videojs.AnStat.prototype._isFound = function(array, elem) {
|
||||
var found = false;
|
||||
for (var indexA in array) {
|
||||
if(typeof array[indexA].second !== 'undefined' && array[indexA].second == elem)
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
};
|
||||
|
||||
videojs.AnStat.prototype._getNumberAnnotations = function(time, end) {
|
||||
var num = (typeof end !== 'undefined' && end) ? -1 : 0;
|
||||
var allannotations = this.an.annotator.plugins['Store'].annotations;
|
||||
for (var index in allannotations) {
|
||||
var an = allannotations[index];
|
||||
if (this.an._isVideoJS(an)) {
|
||||
if(an.rangeTime.start <= time && an.rangeTime.end >= time)
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
};
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplayScroll
|
||||
|
||||
/**
|
||||
* The background annotations panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.BackAnDisplayScroll = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
this.UpValue = 0.1;
|
||||
this.currentValue = 0;
|
||||
}
|
||||
});
|
||||
|
||||
videojs.BackAnDisplayScroll.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
this.mousedownID = -1;
|
||||
var self = this;
|
||||
var direction;
|
||||
|
||||
// Firefox
|
||||
$(this.an.AnDisplay.el_).bind('DOMMouseScroll', function(e) {
|
||||
if (e.originalEvent.detail > 0)
|
||||
direction = self.UpValue;
|
||||
else
|
||||
direction = -self.UpValue;
|
||||
self.an.backDSBarSel.setPosition(self.getPercentScroll() + direction);
|
||||
return false;
|
||||
});
|
||||
|
||||
// IE, Opera, Safari
|
||||
$(this.an.AnDisplay.el_).bind('mousewheel', function(e) {
|
||||
if (e.originalEvent.wheelDelta < 0)
|
||||
direction = self.UpValue;
|
||||
else
|
||||
direction = -self.UpValue;
|
||||
self.an.backDSBarSel.setPosition(self.getPercentScroll() + direction);
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScroll.prototype.options_ = {
|
||||
children: {
|
||||
'BackAnDisplayScrollBar': {},
|
||||
'BackAnDisplayScrollTime': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScroll.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-scroll-anpanel-annotation',
|
||||
innerHTML: '<div class="vjs-up-scroll-annotation"></div><div class="vjs-down-scroll-annotation"></div>',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScroll.prototype.onMouseDown = function(event) {
|
||||
var self = this;
|
||||
if (event.target.className === 'vjs-scrollbar-anpanel-annotation') {
|
||||
// change position with a click in the scrollbar
|
||||
this.an.backDSBarSel.onMouseMove(event);
|
||||
return false;
|
||||
} else if (event.target.className === 'vjs-scrollbar-selector') {
|
||||
// change position with scrollbar
|
||||
// this event is controlled by this.an.backDSBarSel
|
||||
return false;
|
||||
} else {
|
||||
// change position with arrows
|
||||
var direction = event.target.className=='vjs-down-scroll-annotation' ? this.UpValue : -this.UpValue;
|
||||
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
|
||||
if(parseInt(this.mousedownID, 10) === -1) { // Prevent multimple loops!
|
||||
this.mousedownID = setInterval(function () {
|
||||
var pos = Math.max(0, Math.min(1, self.getPercentScroll() + direction));
|
||||
self.an.backDSBarSel.setPosition(pos);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScroll.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
var self = this;
|
||||
if(parseInt(this.mousedownID, 10) != -1) { // Only stop if exists
|
||||
clearInterval(this.mousedownID);
|
||||
self.mousedownID = -1;
|
||||
}
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScroll.prototype.getPercentScroll = function() {
|
||||
var scroll = this.an.AnDisplay.el_;
|
||||
var maxscroll = scroll.scrollHeight - scroll.offsetHeight;
|
||||
var currentValue = scroll.scrollTop;
|
||||
return Math.max(0, Math.min(1, maxscroll !== 0 ? (currentValue / maxscroll) : 0));
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScroll.prototype.setPercentScroll = function(percent) {
|
||||
var scroll = this.an.AnDisplay.el_;
|
||||
var maxscroll = scroll.scrollHeight-scroll.offsetHeight;
|
||||
percent = Math.max(0, Math.min(1, percent ? percent : 0));
|
||||
scroll.scrollTop = Math.round(maxscroll * percent);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollBar
|
||||
|
||||
/**
|
||||
* The Scroll bar for the display
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.BackAnDisplayScrollBar = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.BackAnDisplayScrollBar.prototype.init_ = function() {};
|
||||
|
||||
videojs.BackAnDisplayScrollBar.prototype.options_ = {
|
||||
children: {
|
||||
'ScrollBarSelector': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScrollBar.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-scrollbar-anpanel-annotation',
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollBar--> ScrollBarSelector
|
||||
|
||||
/**
|
||||
* The Scroll bar for the display
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
videojs.ScrollBarSelector = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.ScrollBarSelector.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
videojs.addClass(this.an.backDSBar.el_, 'disable');
|
||||
};
|
||||
|
||||
|
||||
videojs.ScrollBarSelector.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-scrollbar-selector',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.ScrollBarSelector.prototype.onMouseDown = function(event) {
|
||||
event.preventDefault();
|
||||
videojs.on(document, "mousemove", videojs.bind(this, this.onMouseMove));
|
||||
videojs.on(document, "mouseup", videojs.bind(this, this.onMouseUp));
|
||||
}
|
||||
|
||||
videojs.ScrollBarSelector.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mousemove", this.onMouseMove, false);
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
};
|
||||
|
||||
videojs.ScrollBarSelector.prototype.onMouseMove = function(event) {
|
||||
var top = this.calculateDistance(event);
|
||||
top = this.parseMaxPercent(top); // set the max value fixing the height of the handle
|
||||
this.setPosition(top);
|
||||
}
|
||||
|
||||
videojs.ScrollBarSelector.prototype.calculateDistance = function(event) {
|
||||
var scrollY = this.getscrollY();
|
||||
var scrollH = this.getscrollHeight();
|
||||
var handleH = this.getHeight();
|
||||
|
||||
// Adjusted X and Width, so handle doesn't go outside the bar
|
||||
scrollY = scrollY + (handleH);
|
||||
scrollH = scrollH - (handleH);
|
||||
// Adjusted X and Width, so handle doesn't go outside the bar
|
||||
// Percent that the click is through the adjusted area
|
||||
return Math.max(0, Math.min(1, (event.pageY - scrollY) / scrollH));
|
||||
};
|
||||
|
||||
videojs.ScrollBarSelector.prototype.getscrollHeight = function() {
|
||||
return this.el_.parentNode.offsetHeight;
|
||||
};
|
||||
videojs.ScrollBarSelector.prototype.getscrollY = function() {
|
||||
return videojs.findPosition(this.el_.parentNode).top;
|
||||
};
|
||||
videojs.ScrollBarSelector.prototype.getHeight = function() {
|
||||
return this.el_.offsetHeight;
|
||||
};
|
||||
videojs.ScrollBarSelector.prototype.parseMaxHeight = function(top) {
|
||||
var scrollH = this.getscrollHeight();
|
||||
var handleH = this.getHeight();
|
||||
var percent = handleH / scrollH;
|
||||
return Math.max(0, Math.min(1 - percent, top));
|
||||
};
|
||||
|
||||
videojs.ScrollBarSelector.prototype.parseMaxPercent = function(top) {
|
||||
var scrollH = this.getscrollHeight();
|
||||
var handleH = this.getHeight();
|
||||
var percent = handleH / scrollH;
|
||||
var newTop = top;
|
||||
if (top >= (1 - percent))
|
||||
newTop = 1;
|
||||
return newTop;
|
||||
};
|
||||
|
||||
videojs.ScrollBarSelector.prototype.setPosition = function(top, showBar) {
|
||||
var showBar = typeof showBar !== 'undefined' ? showBar : true;
|
||||
|
||||
// Check for invalid position
|
||||
if (isNaN(top))
|
||||
return false;
|
||||
|
||||
// Check if there is enough annotations to scroll
|
||||
if (!this.isScrollable())
|
||||
return false;
|
||||
|
||||
// Show the Scrollbar
|
||||
if (showBar) {
|
||||
videojs.removeClass(this.an.backDSBar.el_, 'disable')
|
||||
}
|
||||
|
||||
// Alias
|
||||
var Obj = this.el_;
|
||||
var scroll = this.an.BackAnDisplayScroll;
|
||||
var scrollTime = this.an.backDSTime;
|
||||
|
||||
Obj.style.top = (this.parseMaxHeight(top) * 100) + '%';
|
||||
scroll.setPercentScroll(top);
|
||||
|
||||
// Set the times in the scroll time panel
|
||||
scrollTime.setTimes();
|
||||
|
||||
// Hide the Scrollbar in 1 sec
|
||||
if(showBar) {
|
||||
var _self = this;
|
||||
if (typeof this.Timeout !== 'undefined')
|
||||
clearTimeout(this.Timeout);
|
||||
this.Timeout = window.setTimeout(function () {
|
||||
videojs.addClass(_self.an.backDSBar.el_, 'disable');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// set current position
|
||||
this.an.BackAnDisplayScroll.currentValue = top;
|
||||
return true;
|
||||
}
|
||||
|
||||
videojs.ScrollBarSelector.prototype.isScrollable = function() {
|
||||
var scroll = this.an.AnDisplay.el_;
|
||||
var emtoPx = parseFloat($(scroll).find('.annotation').css('height'));
|
||||
var minTop = parseInt(scroll.offsetHeight/emtoPx);
|
||||
|
||||
// Count visible annotations in Panel
|
||||
var count = this.an.AnDisplay.countVisibles();
|
||||
return (count > minTop);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -- Player--> ControlBar--> BackAnDisplayScroll--> BackAnDisplayScrollTime
|
||||
|
||||
videojs.BackAnDisplayScrollTime = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options) {
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.BackAnDisplayScrollTime.prototype.init_ = function() {
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.an = this.player_.annotations;
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScrollTime.prototype.createEl = function() {
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-scrolltime-anpanel-annotation',
|
||||
innerHTML: '<div class="vjs-up-scrolltime-annotation"><span class="vjs-time-text"></span></div><div class="vjs-down-scrolltime-annotation"><span class="vjs-time-text"></span></div>',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScrollTime.prototype.setTimes = function() {
|
||||
var AnPos = this.getAnnotationPosition();
|
||||
var AnEl = this.getElements(AnPos);
|
||||
var AnTimes = this.getTimes(AnEl);
|
||||
if (AnTimes.top != 'Invalid Date') {
|
||||
$(this.el_).find('.vjs-up-scrolltime-annotation')[0].style.visibility = '';
|
||||
$(this.el_).find('.vjs-up-scrolltime-annotation span')[0].innerHTML = AnTimes.top;
|
||||
} else {
|
||||
$(this.el_).find('.vjs-up-scrolltime-annotation')[0].style.visibility = 'hidden';
|
||||
}
|
||||
if (AnTimes.bottom != 'Invalid Date') {
|
||||
$(this.el_).find('.vjs-down-scrolltime-annotation')[0].style.visibility = '';
|
||||
$(this.el_).find('.vjs-down-scrolltime-annotation span')[0].innerHTML = AnTimes.bottom;
|
||||
} else {
|
||||
$(this.el_).find('.vjs-down-scrolltime-annotation')[0].style.visibility = 'hidden';
|
||||
}
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScrollTime.prototype.getAnnotationPosition = function() {
|
||||
var backDSBarSel = this.an.backDSBarSel;
|
||||
var percent = backDSBarSel.parseMaxPercent(parseFloat(backDSBarSel.el_.style.top) / 100);
|
||||
var scroll = this.an.AnDisplay.el_;
|
||||
var maxTop = scroll.scrollHeight;
|
||||
var minTop = scroll.offsetHeight;
|
||||
var maxBottom = maxTop - minTop;
|
||||
var minBottom = 0;
|
||||
var pos = {};
|
||||
|
||||
percent = percent || 0;
|
||||
pos.top = Math.max(minTop, Math.min(maxTop, maxBottom * percent + scroll.offsetHeight));
|
||||
pos.bottom = Math.max(minBottom, Math.min(maxBottom, maxBottom * percent));
|
||||
return pos;
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScrollTime.prototype.getElements = function(AnPos) {
|
||||
var AnPos = AnPos || {};
|
||||
var scroll = this.an.AnDisplay.el_;
|
||||
var emtoPx = parseFloat($(scroll).find('.annotation').css('height'));
|
||||
var maxTop = parseInt(scroll.scrollHeight / emtoPx);
|
||||
var minTop = parseInt(scroll.offsetHeight / emtoPx);
|
||||
var maxBottom = (maxTop - minTop);
|
||||
var minBottom = 0;
|
||||
var AnEl = {};
|
||||
AnEl.top = Math.max(minTop, Math.min(maxTop, parseInt(AnPos.top / emtoPx)));
|
||||
AnEl.bottom = Math.max(minBottom, Math.min(maxBottom, parseInt(AnPos.bottom / emtoPx)));
|
||||
return AnEl;
|
||||
};
|
||||
|
||||
videojs.BackAnDisplayScrollTime.prototype.getTimes = function(AnEl) {
|
||||
var AnEl = AnEl || {};
|
||||
var AnTimes = {};
|
||||
var TopEl, BottomEl, AnTop, AnBottom;
|
||||
var AnArray = $.makeArray(this.an.AnDisplay.el_.children);
|
||||
AnEl.top = AnEl.top || 0;
|
||||
AnEl.bottom = AnEl.bottom || 0;
|
||||
|
||||
// Get HTML Elements
|
||||
var count = 0;
|
||||
var lastEl;
|
||||
for (var index in AnArray) {
|
||||
var an = AnArray[index];
|
||||
if (an.style.display !== 'none') {
|
||||
if (count == AnEl.bottom) {
|
||||
TopEl = an;
|
||||
} else if (count == AnEl.top) {
|
||||
BottomEl = an;
|
||||
}
|
||||
lastEl = an;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (typeof BottomEl === 'undefined')
|
||||
BottomEl = lastEl;
|
||||
|
||||
// Annotation Element
|
||||
AnTop = typeof TopEl !== 'undefined' ? $.data(TopEl, 'annotation') : undefined;
|
||||
AnBottom = typeof BottomEl !== 'undefined' ? $.data(BottomEl, 'annotation') : undefined;
|
||||
// Update of the element
|
||||
AnTimes.top = (typeof AnTop !== 'undefined' && typeof AnTop.updated !== 'undefined') ? AnTop.updated : '';
|
||||
AnTimes.bottom = (typeof AnBottom !=='undefined' && typeof AnBottom.updated !== 'undefined') ? AnBottom.updated : '';
|
||||
// Format
|
||||
AnTimes.top = new Date(AnTimes.top !== '' ? createDateFromISO8601(AnTimes.top) : '');
|
||||
AnTimes.bottom = new Date(AnTimes.bottom != '' ? createDateFromISO8601(AnTimes.bottom) : '');
|
||||
return AnTimes;
|
||||
};
|
||||
}) ();
|
||||
|
||||
// ----------------Plugin for Annotator to setup videojs---------------- //
|
||||
|
||||
Annotator.Plugin.VideoJS = (function(_super) {
|
||||
__extends(VideoJS, _super);
|
||||
|
||||
// constructor
|
||||
function VideoJS() {
|
||||
this.pluginSubmit = __bind(this.pluginSubmit, this);
|
||||
_ref = VideoJS.__super__.constructor.apply(this, arguments);
|
||||
this.__indexOf = [].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;
|
||||
};
|
||||
|
||||
VideoJS.prototype.field = null;
|
||||
VideoJS.prototype.input = null;
|
||||
|
||||
VideoJS.prototype.pluginInit = function() {
|
||||
console.log("VideoJS-pluginInit");
|
||||
// Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// -- Editor
|
||||
this.field = this.annotator.editor.addField({
|
||||
id: 'vjs-input-rangeTime-annotations',
|
||||
type: 'input', // options (textarea, input, select, checkbox)
|
||||
submit: this.pluginSubmit,
|
||||
EditVideoAn: this.EditVideoAn
|
||||
});
|
||||
|
||||
// Modify the element created with annotator to be an invisible span
|
||||
var select = '<li><span id="vjs-input-rangeTime-annotations"></span></li>';
|
||||
var newfield = Annotator.$(select);
|
||||
Annotator.$(this.field).replaceWith(newfield);
|
||||
this.field = newfield[0];
|
||||
|
||||
// -- Listener for Open Video Annotator
|
||||
this.initListeners();
|
||||
|
||||
return this.input = $(this.field).find(':input');
|
||||
};
|
||||
|
||||
|
||||
// New JSON for the database
|
||||
VideoJS.prototype.pluginSubmit = function(field, annotation) {
|
||||
console.log("Plug-pluginSubmit");
|
||||
// Select the new JSON for the Object to save
|
||||
if (this.EditVideoAn()) {
|
||||
var annotator = this.annotator;
|
||||
var index = annotator.editor.VideoJS;
|
||||
var player = annotator.mplayer[index];
|
||||
var rs = player.rangeslider;
|
||||
var time = rs.getValues();
|
||||
var isYoutube = (player && typeof player.techName !== 'undefined') ? (player.techName === 'Youtube') : false;
|
||||
var isNew = typeof annotation.media === 'undefined';
|
||||
var ext;
|
||||
var type = player.options_.sources[0].type.split("/") || "";
|
||||
|
||||
if (isNew)
|
||||
annotation.media = typeof type[0] !== 'undefined' ? type[0] : "video"; // - media (by default: video)
|
||||
|
||||
annotation.target = annotation.target || {}; // - target
|
||||
annotation.target.container = player.id_ || ""; // - target.container
|
||||
annotation.target.src = player.options_.sources[0].src || ""; // - target.src (media source)
|
||||
ext = (player.options_.sources[0].src.substring(player.options_.sources[0].src.lastIndexOf("."))).toLowerCase();
|
||||
ext = isYoutube ? 'Youtube' : ext; // The extension for youtube
|
||||
annotation.target.ext = ext || ""; // - target.ext (extension)
|
||||
annotation.rangeTime = annotation.rangeTime || {}; // - rangeTime
|
||||
annotation.rangeTime.start = time.start || 0; // - rangeTime.start
|
||||
annotation.rangeTime.end = time.end || 0; // - rangeTime.end
|
||||
annotation.updated = new Date().toISOString(); // - updated
|
||||
if (typeof annotation.created === 'undefined')
|
||||
annotation.created = annotation.updated; // - created
|
||||
|
||||
// show the new annotation
|
||||
var eventAn = isNew ? "annotationCreated" : "annotationUpdated";
|
||||
function afterFinish(){
|
||||
player.annotations.showAnnotation(annotation);
|
||||
annotator.unsubscribe(eventAn, afterFinish);
|
||||
};
|
||||
annotator.subscribe(eventAn, afterFinish); // show after the annotation is in the back-end
|
||||
} 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 a video-js annotation
|
||||
VideoJS.prototype.EditVideoAn = function () {
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = window.annotator = $.data(wrapper, 'annotator');
|
||||
var isOpenVideojs = (typeof annotator.mplayer !== 'undefined');
|
||||
var VideoJS = annotator.editor.VideoJS;
|
||||
return (isOpenVideojs && typeof VideoJS !== 'undefined' && VideoJS !== -1);
|
||||
};
|
||||
|
||||
|
||||
// Detect if the annotation is a video-js annotation
|
||||
VideoJS.prototype.isVideoJS = function (an) {
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = window.annotator = $.data(wrapper, 'annotator');
|
||||
var rt = an.rangeTime;
|
||||
var isOpenVideojs = (typeof annotator.mplayer !== 'undefined');
|
||||
var isVideo = (typeof an.media !== 'undefined' && (an.media === 'video' || an.media === 'audio'));
|
||||
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
|
||||
return (isOpenVideojs && isVideo && isNumber);
|
||||
};
|
||||
|
||||
// Delete Video Annotation
|
||||
VideoJS.prototype._deleteAnnotation = function(an) {
|
||||
var target = an.target || {};
|
||||
var container = target.container || {};
|
||||
var player = this.annotator.mplayer[container];
|
||||
|
||||
var annotator = this.annotator;
|
||||
var annotations = annotator.plugins.Store.annotations;
|
||||
var tot = typeof annotations !== 'undefined' ? annotations.length : 0;
|
||||
var attempts = 0; // max 100
|
||||
|
||||
// This is to watch the annotations object, to see when is deleted the annotation
|
||||
var ischanged = function() {
|
||||
var new_tot = annotator.plugins.Store.annotations.length;
|
||||
if (attempts < 100)
|
||||
setTimeout(function() {
|
||||
if (new_tot !== tot) {
|
||||
player.annotations.refreshDisplay(); // Reload the display of annotation
|
||||
} else {
|
||||
attempts++;
|
||||
ischanged();
|
||||
}
|
||||
}, 100); // wait for the change in the annotations
|
||||
};
|
||||
ischanged();
|
||||
|
||||
player.rangeslider.hide(); // Hide Range Slider
|
||||
};
|
||||
|
||||
|
||||
// --Listeners
|
||||
VideoJS.prototype.initListeners = function () {
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var annotator = $.data(wrapper, 'annotator');
|
||||
var EditVideoAn = this.EditVideoAn;
|
||||
var isVideoJS = this.isVideoJS;
|
||||
var self = this;
|
||||
|
||||
// local functions
|
||||
// -- Editor
|
||||
function annotationEditorHidden(editor) {
|
||||
if (EditVideoAn()){
|
||||
var index = annotator.editor.VideoJS;
|
||||
annotator.mplayer[index].rangeslider.hide(); // Hide Range Slider
|
||||
annotator.an[index].refreshDisplay(); // Reload the display of annotations
|
||||
}
|
||||
annotator.editor.VideoJS=-1;
|
||||
annotator.unsubscribe("annotationEditorHidden", annotationEditorHidden);
|
||||
};
|
||||
function annotationEditorShown(editor, annotation) {
|
||||
for (var index in annotator.an){
|
||||
annotator.an[index].editAnnotation(annotation, editor);
|
||||
}
|
||||
annotator.subscribe("annotationEditorHidden", annotationEditorHidden);
|
||||
};
|
||||
// -- Annotations
|
||||
function annotationDeleted(annotation) {
|
||||
|
||||
if (isVideoJS(annotation))
|
||||
self._deleteAnnotation(annotation);
|
||||
};
|
||||
// -- Viewer
|
||||
function hideViewer(){
|
||||
for (var index in annotator.an) {
|
||||
annotator.an[index].AnDisplay.onCloseViewer();
|
||||
}
|
||||
annotator.viewer.unsubscribe("hide", hideViewer);
|
||||
};
|
||||
function annotationViewerShown(viewer, annotations) {
|
||||
|
||||
var separation = viewer.element.hasClass(viewer.classes.invert.y) ? 5 : -5;
|
||||
var newpos = {
|
||||
top: parseFloat(viewer.element[0].style.top)+separation,
|
||||
left: parseFloat(viewer.element[0].style.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 VideoJS;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
|
||||
|
||||
// ----------------PUBLIC OBJECT TO CONTROL THE ANNOTATIONS---------------- //
|
||||
|
||||
// The name of the plugin that the user will write in the html
|
||||
OpenVideoAnnotation = ("OpenVideoAnnotation" in window) ? OpenVideoAnnotation : {};
|
||||
|
||||
OpenVideoAnnotation.Annotator = function (element, options) {
|
||||
// local variables
|
||||
var $ = jQuery;
|
||||
var options = options || {};
|
||||
options.optionsAnnotator = options.optionsAnnotator || {};
|
||||
options.optionsVideoJS = options.optionsVideoJS || {};
|
||||
options.optionsRS = options.optionsRS || {};
|
||||
options.optionsOVA = options.optionsOVA || {};
|
||||
|
||||
|
||||
// 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');
|
||||
options.optionsOVA.optionsAnnotator = options.optionsAnnotator.annotator; // send the Annotator's options to OVA
|
||||
|
||||
|
||||
// Video-JS
|
||||
/*
|
||||
mplayers -> Array with the html of all the video-js
|
||||
mplayer -> Array with all the video-js that will be in the plugin
|
||||
*/
|
||||
var mplayers = $(element).find('div .video-js').toArray();
|
||||
var mplayer = this.mplayer = {};
|
||||
for (var index in mplayers) {
|
||||
var id = mplayers[index].id;
|
||||
var mplayer_ = videojs(mplayers[index], options.optionsVideoJS);
|
||||
// solve a problem with firefox. In Firefox the src() function is loaded before charge the optionsVideoJS, and the techOrder are not loaded
|
||||
if (vjs.IS_FIREFOX && typeof options.optionsVideoJS.techOrder !== 'undefined'){
|
||||
mplayer_.options_.techOrder = options.optionsVideoJS.techOrder;
|
||||
mplayer_.src(mplayer_.options_['sources']);
|
||||
}
|
||||
this.mplayer[id] = mplayer_;
|
||||
}
|
||||
|
||||
|
||||
// Video-JS
|
||||
this.annotator.an = {}; // annotations video-js plugin to annotator
|
||||
for (var index in this.mplayer) {
|
||||
// to be their own options is necessary to extend deeply the options with all the childrens
|
||||
this.mplayer[index].rangeslider($.extend(true, {}, options.optionsRS));
|
||||
this.mplayer[index].annotations($.extend(true, {}, options.optionsOVA));
|
||||
this.annotator.an[index]=this.mplayer[index].annotations;
|
||||
}
|
||||
|
||||
|
||||
// -- Experimental Global function for Open Video Annotator -- //
|
||||
this.setCurrentUser = function (user) {
|
||||
this.currentUser = user;
|
||||
this.annotator.plugins["Permissions"].setUser(user);
|
||||
}
|
||||
|
||||
// Local function to setup the keyboard listener
|
||||
var focusedPlayer = this.focusedPlayer = ''; // variable to know the focused player
|
||||
var lastfocusPlayer = this.lastfocusPlayer = '';
|
||||
|
||||
function onKeyUp(e) {
|
||||
// skip the text areas
|
||||
if (e.target.nodeName.toLowerCase() !== 'textarea')
|
||||
mplayer[focusedPlayer].annotations.pressedKey(e.which);
|
||||
};
|
||||
|
||||
(this._setupKeyboard = function() {
|
||||
$(document).mousedown(function(e) {
|
||||
focusedPlayer = '';
|
||||
|
||||
// Detects if a player was click
|
||||
for (var index in mplayer) {
|
||||
if ($(mplayer[index].el_).find(e.target).length)
|
||||
focusedPlayer = mplayer[index].id_;
|
||||
}
|
||||
|
||||
// Enter if we change the focus between player or go out of the player
|
||||
if (lastfocusPlayer !== focusedPlayer) {
|
||||
$(document).off("keyup", onKeyUp); // Remove the last listener
|
||||
// set the key listener
|
||||
if (focusedPlayer !== '')
|
||||
$(document).on("keyup", onKeyUp);
|
||||
}
|
||||
|
||||
lastfocusPlayer = focusedPlayer;
|
||||
});
|
||||
|
||||
}) (this);
|
||||
|
||||
// -- Activate all the plugins -- //
|
||||
// Annotator
|
||||
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 options.optionsAnnotator.diacriticMarks !== 'undefined' && typeof Annotator.Plugin["Diacritics"] === 'function')
|
||||
this.annotator.addPlugin("Diacritics", options.optionsAnnotator.diacriticMarks);
|
||||
|
||||
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);
|
||||
|
||||
this.annotator.addPlugin("VideoJS"); // it is obligatory to have
|
||||
|
||||
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["Flagging"] === 'function')
|
||||
this.annotator.addPlugin("Flagging");
|
||||
|
||||
if (typeof options.optionsAnnotator.highlightTags !== 'undefined')
|
||||
this.annotator.addPlugin("HighlightTags", options.optionsAnnotator.highlightTags);
|
||||
|
||||
// Will be add the player and the annotations plugin for video-js in the annotator
|
||||
this.annotator.mplayer = this.mplayer;
|
||||
this.annotator.editor.VideoJS = -1;
|
||||
|
||||
this.options = options;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------Local Functions for Open Video Annotator---------------- //
|
||||
|
||||
// --local functions
|
||||
// if the annotation is a video return true
|
||||
OpenVideoAnnotation.Annotator.prototype._isVideo = function(an) {
|
||||
// Detect if the annotation is a Open Video Annotation
|
||||
var an = an || {};
|
||||
var rt = an.rangeTime;
|
||||
var isVideo = (typeof an.media !== 'undefined' && (an.media === 'video' || an.media === 'audio'));
|
||||
var hasContainer = (typeof an.target !== 'undefined' && typeof an.target.container !== 'undefined');
|
||||
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
|
||||
return (isVideo && hasContainer && isNumber);
|
||||
}
|
||||
|
||||
// if the ova has been loaded and the video is opened return true
|
||||
OpenVideoAnnotation.Annotator.prototype._isloaded = function(idElem) {
|
||||
return typeof this.mplayer[idElem].annotations.loaded !== 'undefined';
|
||||
}
|
||||
|
||||
// ----------------Public Functions for Open Video Annotator---------------- //
|
||||
|
||||
// Create a new video annotation
|
||||
OpenVideoAnnotation.Annotator.prototype.newVideoAn = function(idElem) {
|
||||
var player = this.mplayer[idElem];
|
||||
if (typeof player.play !== 'undefined') {
|
||||
player.play();
|
||||
player.one('playing', function() {
|
||||
player.annotations.newan();
|
||||
$('html, body').animate({
|
||||
scrollTop: $("#" + player.id_).offset().top
|
||||
}, 'slow');
|
||||
player.pause();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Show the annotation display
|
||||
OpenVideoAnnotation.Annotator.prototype.showDisplay = function(idElem) {
|
||||
if (this._isloaded(idElem))
|
||||
return this.mplayer[idElem].annotations.showDisplay();
|
||||
};
|
||||
|
||||
// Hide the annotation display
|
||||
OpenVideoAnnotation.Annotator.prototype.hideDisplay = function(idElem) {
|
||||
if (this._isloaded(idElem))
|
||||
return this.mplayer[idElem].annotations.hideDisplay();
|
||||
};
|
||||
|
||||
// Refresh the annotation display
|
||||
OpenVideoAnnotation.Annotator.prototype.refreshDisplay = function(idElem) {
|
||||
if (this._isloaded(idElem))
|
||||
return this.mplayer[idElem].annotations.hideDisplay();
|
||||
};
|
||||
|
||||
// Set the position of the big new annotation button
|
||||
OpenVideoAnnotation.Annotator.prototype.setposBigNew = function(idElem, position) {
|
||||
if (this._isloaded(idElem))
|
||||
return this.mplayer[idElem].annotations.setposBigNew(position);
|
||||
};
|
||||
|
||||
OpenVideoAnnotation.Annotator.prototype.playTarget = function (annotationId) {
|
||||
var allannotations = this.annotator.plugins.Store.annotations;
|
||||
var ovaId = annotationId;
|
||||
var mplayer = this.mplayer;
|
||||
|
||||
for (var item in allannotations) {
|
||||
var an = allannotations[item];
|
||||
if (typeof an.id != 'undefined' && an.id == ovaId) { // this is the annotation
|
||||
if (this._isVideo(an)) { // It is a video
|
||||
for (var index in mplayer) {
|
||||
var player = mplayer[index];
|
||||
if (player.id_ == an.target.container && player.tech.options_.source.src === an.target.src){
|
||||
var anFound = an;
|
||||
|
||||
var playFunction = function() {
|
||||
// Fix problem with youtube videos in the first play. The plugin don't have this trigger
|
||||
if (player.techName === 'Youtube') {
|
||||
var startAPI = function() {
|
||||
player.annotations.showAnnotation(anFound);
|
||||
}
|
||||
if (player.annotations.loaded)
|
||||
startAPI();
|
||||
else
|
||||
player.one('loadedRangeSlider', startAPI); // show Annotations once the RangeSlider is loaded
|
||||
} else {
|
||||
player.annotations.showAnnotation(anFound);
|
||||
}
|
||||
|
||||
$('html, body').animate({
|
||||
scrollTop: $("#"+player.id_).offset().top
|
||||
}, 'slow');
|
||||
};
|
||||
if (player.paused()) {
|
||||
player.play();
|
||||
player.one('playing', playFunction);
|
||||
} else {
|
||||
playFunction();
|
||||
}
|
||||
|
||||
return false; // this will stop the code to not set a new player.one.
|
||||
}
|
||||
}
|
||||
} else { // It is a text
|
||||
var hasRanges = typeof an.ranges !== 'undefined' && typeof an.ranges[0] !== 'undefined';
|
||||
var startOffset = hasRanges ? an.ranges[0].startOffset : '';
|
||||
var endOffset = hasRanges ? an.ranges[0].endOffset : '';
|
||||
|
||||
if (typeof startOffset !== 'undefined' && typeof endOffset !== 'undefined') {
|
||||
|
||||
$(an.highlights).parent().find('.annotator-hl').removeClass('api');
|
||||
// change the color
|
||||
$(an.highlights).addClass('api');
|
||||
// animate to the annotation
|
||||
$('html, body').animate({
|
||||
scrollTop: $(an.highlights[0]).offset().top
|
||||
}, 'slow');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1078
common/static/js/vendor/ova/rangeslider.js
vendored
@@ -1,1078 +0,0 @@
|
||||
/*
|
||||
RangeSlider v1.0 (https://github.com/danielcebrian/rangeslider-videojs)
|
||||
Copyright (C) 2014 Daniel Cebrian Robles
|
||||
License: https://github.com/danielcebrian/rangeslider-videojs/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.
|
||||
*/
|
||||
//----------------Load Plugin----------------//
|
||||
(function (){
|
||||
//-- Load RangeSlider plugin in videojs
|
||||
function RangeSlider_(options){
|
||||
var player = this;
|
||||
|
||||
player.rangeslider=new RangeSlider(player, options);
|
||||
|
||||
//When the DOM and the video media is loaded
|
||||
function initialVideoFinished(event) {
|
||||
var plugin = player.rangeslider;
|
||||
//All components will be initialize after they have been loaded by videojs
|
||||
for (var index in plugin.components) {
|
||||
plugin.components[index].init_();
|
||||
}
|
||||
|
||||
if (plugin.options.hidden)
|
||||
plugin.hide(); //Hide the Range Slider
|
||||
|
||||
if(plugin.options.locked)
|
||||
plugin.lock(); //Lock the Range Slider
|
||||
|
||||
if(plugin.options.panel==false)
|
||||
plugin.hidePanel(); //Hide the second Panel
|
||||
|
||||
if(plugin.options.controlTime==false)
|
||||
plugin.hidecontrolTime(); //Hide the control time panel
|
||||
|
||||
plugin._reset();
|
||||
player.trigger('loadedRangeSlider'); //Let know if the Range Slider DOM is ready
|
||||
}
|
||||
if (player.techName == 'Youtube'){
|
||||
//Detect youtube problems
|
||||
player.one('error', function(e){
|
||||
switch (player.error) {
|
||||
case 2:
|
||||
alert("The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.");
|
||||
case 5:
|
||||
alert("The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.");
|
||||
case 100:
|
||||
alert("The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.");
|
||||
break;
|
||||
case 101:
|
||||
alert("The owner of the requested video does not allow it to be played in embedded players.");
|
||||
break;
|
||||
case 150:
|
||||
alert("The owner of the requested video does not allow it to be played in embedded players.");
|
||||
break;
|
||||
default:
|
||||
alert("Unknown Error");
|
||||
break;
|
||||
}
|
||||
});
|
||||
player.on('firstplay', initialVideoFinished);
|
||||
}else{
|
||||
player.one('playing', initialVideoFinished);
|
||||
}
|
||||
|
||||
|
||||
console.log("Loaded Plugin RangeSlider");
|
||||
}
|
||||
videojs.plugin('rangeslider', RangeSlider_);
|
||||
|
||||
|
||||
|
||||
//-- Plugin
|
||||
function RangeSlider(player,options){
|
||||
var player = player || this;
|
||||
|
||||
this.player = player;
|
||||
|
||||
this.components = {}; // holds any custom components we add to the player
|
||||
|
||||
options = options || {}; // plugin options
|
||||
|
||||
if(!options.hasOwnProperty('locked'))
|
||||
options.locked = false; // lock slider handles
|
||||
|
||||
if(!options.hasOwnProperty('hidden'))
|
||||
options.hidden = true; // hide slider handles
|
||||
|
||||
if(!options.hasOwnProperty('panel'))
|
||||
options.panel = true; // Show Second Panel
|
||||
|
||||
if(!options.hasOwnProperty('controlTime'))
|
||||
options.controlTime = true; // Show Control Time to set the arrows in the edition
|
||||
|
||||
this.options = options;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
//-- Methods
|
||||
RangeSlider.prototype = {
|
||||
/*Constructor*/
|
||||
init:function(){
|
||||
var player = this.player || {};
|
||||
|
||||
this.updatePrecision = 3;
|
||||
|
||||
//position in second of the arrows
|
||||
this.start = 0;
|
||||
this.end = 0;
|
||||
|
||||
//components of the plugin
|
||||
var controlBar = player.controlBar;
|
||||
var seekBar = controlBar.progressControl.seekBar;
|
||||
this.components.RSTimeBar = seekBar.RSTimeBar;
|
||||
this.components.ControlTimePanel = controlBar.ControlTimePanel;
|
||||
|
||||
//Save local component
|
||||
this.rstb = this.components.RSTimeBar;
|
||||
this.box = this.components.SeekRSBar = this.rstb.SeekRSBar;
|
||||
this.bar = this.components.SelectionBar = this.box.SelectionBar;
|
||||
this.left = this.components.SelectionBarLeft = this.box.SelectionBarLeft;
|
||||
this.right = this.components.SelectionBarRight = this.box.SelectionBarRight;
|
||||
this.tp = this.components.TimePanel = this.box.TimePanel;
|
||||
this.tpl = this.components.TimePanelLeft = this.tp.TimePanelLeft;
|
||||
this.tpr = this.components.TimePanelRight = this.tp.TimePanelRight;
|
||||
this.ctp = this.components.ControlTimePanel;
|
||||
this.ctpl = this.components.ControlTimePanelLeft = this.ctp.ControlTimePanelLeft;
|
||||
this.ctpr = this.components.ControlTimePanelRight = this.ctp.ControlTimePanelRight;
|
||||
|
||||
},
|
||||
lock: function() {
|
||||
this.options.locked = true;
|
||||
this.ctp.enable(false);
|
||||
if (typeof this.box != 'undefined')
|
||||
videojs.addClass(this.box.el_, 'locked');
|
||||
},
|
||||
unlock: function() {
|
||||
this.options.locked = false;
|
||||
this.ctp.enable();
|
||||
if (typeof this.box !='undefined')
|
||||
videojs.removeClass(this.box.el_, 'locked');
|
||||
},
|
||||
show:function(){
|
||||
this.options.hidden = false;
|
||||
if (typeof this.rstb !='undefined'){
|
||||
this.rstb.show();
|
||||
if (this.options.controlTime)
|
||||
this.showcontrolTime();
|
||||
}
|
||||
},
|
||||
hide:function(){
|
||||
this.options.hidden = true;
|
||||
if (typeof this.rstb !='undefined'){
|
||||
this.rstb.hide();
|
||||
this.ctp.hide();
|
||||
}
|
||||
},
|
||||
showPanel:function(){
|
||||
this.options.panel = true;
|
||||
if (typeof this.tp !='undefined')
|
||||
videojs.removeClass(this.tp.el_, 'disable');
|
||||
},
|
||||
hidePanel:function(){
|
||||
this.options.panel = false;
|
||||
if (typeof this.tp !='undefined')
|
||||
videojs.addClass(this.tp.el_, 'disable');
|
||||
},
|
||||
showcontrolTime:function(){
|
||||
this.options.controlTime = true;
|
||||
if (typeof this.ctp !='undefined')
|
||||
this.ctp.show();
|
||||
},
|
||||
hidecontrolTime:function(){
|
||||
this.options.controlTime = false;
|
||||
if (typeof this.ctp !='undefined')
|
||||
this.ctp.hide();
|
||||
},
|
||||
setValue: function(index, seconds, writeControlTime) {
|
||||
//index = 0 for the left Arrow and 1 for the right Arrow. Value in seconds
|
||||
var writeControlTime = typeof writeControlTime!='undefined'?writeControlTime:true;
|
||||
|
||||
var percent = this._percent(seconds);
|
||||
var isValidIndex = (index === 0 || index === 1);
|
||||
var isChangeable = !this.locked;
|
||||
if(isChangeable && isValidIndex)
|
||||
this.box.setPosition(index,percent,writeControlTime);
|
||||
},
|
||||
setValues: function(start, end, writeControlTime) {
|
||||
//index = 0 for the left Arrow and 1 for the right Arrow. Value in seconds
|
||||
var writeControlTime = typeof writeControlTime!='undefined'?writeControlTime:true;
|
||||
|
||||
this._reset();
|
||||
|
||||
this._setValuesLocked(start,end,writeControlTime);
|
||||
},
|
||||
getValues: function() { //get values in seconds
|
||||
var values = {}, start, end;
|
||||
start = this.start || this._getArrowValue(0);
|
||||
end = this.end || this._getArrowValue(1);
|
||||
return {start:start, end:end};
|
||||
},
|
||||
playBetween: function(start, end,showRS) {
|
||||
showRS = typeof showRS == 'undefined'?true:showRS;
|
||||
this.player.currentTime(start);
|
||||
this.player.play();
|
||||
if (showRS){
|
||||
this.show();
|
||||
this._reset();
|
||||
}else{
|
||||
this.hide();
|
||||
}
|
||||
this._setValuesLocked(start,end);
|
||||
|
||||
this.bar.activatePlay(start,end);
|
||||
},
|
||||
loop: function (start, end, show) {
|
||||
var player = this.player;
|
||||
|
||||
if (player) {
|
||||
player.on("pause", videojs.bind(this, function () {
|
||||
this.looping = false;
|
||||
}));
|
||||
|
||||
show = typeof show === 'undefined' ? true : show;
|
||||
|
||||
if (show) {
|
||||
this.show();
|
||||
this._reset();
|
||||
}
|
||||
else {
|
||||
this.hide();
|
||||
}
|
||||
this._setValuesLocked(start, end);
|
||||
|
||||
this.timeStart = start;
|
||||
this.timeEnd = end;
|
||||
this.looping = true;
|
||||
|
||||
this.player.currentTime(start);
|
||||
this.player.play();
|
||||
|
||||
this.player.on("timeupdate", videojs.bind(this, this.bar.process_loop));
|
||||
}
|
||||
},
|
||||
_getArrowValue: function(index) {
|
||||
var index = index || 0;
|
||||
var duration = this.player.duration();
|
||||
|
||||
duration = typeof duration == 'undefined'? 0 : duration;
|
||||
|
||||
var percentage = this[index === 0? "left" : "right"].el_.style.left.replace("%","");
|
||||
if (percentage == "")
|
||||
percentage = index === 0? 0 : 100;
|
||||
|
||||
return videojs.round(this._seconds(percentage / 100),this.updatePrecision-1);
|
||||
},
|
||||
_percent: function(seconds) {
|
||||
var duration = this.player.duration();
|
||||
if(isNaN(duration)) {
|
||||
return 0;
|
||||
}
|
||||
return Math.min(1, Math.max(0, seconds / duration));
|
||||
},
|
||||
_seconds: function(percent) {
|
||||
var duration = this.player.duration();
|
||||
if(isNaN(duration)) {
|
||||
return 0;
|
||||
}
|
||||
return Math.min(duration, Math.max(0, percent * duration));
|
||||
},
|
||||
_reset: function() {
|
||||
var duration = this.player.duration();
|
||||
this.tpl.el_.style.left = '0%';
|
||||
this.tpr.el_.style.left = '100%';
|
||||
this._setValuesLocked(0,duration);
|
||||
},
|
||||
_setValuesLocked: function(start,end, writeControlTime){
|
||||
var triggerSliderChange = typeof writeControlTime!='undefined';
|
||||
var writeControlTime = typeof writeControlTime!='undefined'?writeControlTime:true;
|
||||
if(this.options.locked) {
|
||||
this.unlock();//It is unlocked to change the bar position. In the end it will return the value.
|
||||
this.setValue(0,start,writeControlTime);
|
||||
this.setValue(1,end,writeControlTime);
|
||||
this.lock();
|
||||
}else{
|
||||
this.setValue(0,start,writeControlTime);
|
||||
this.setValue(1,end,writeControlTime);
|
||||
}
|
||||
|
||||
// Trigger slider change
|
||||
if (triggerSliderChange) {
|
||||
this._triggerSliderChange();
|
||||
}
|
||||
},
|
||||
_checkControlTime: function(index,TextInput,timeOld){
|
||||
var h = TextInput[0],
|
||||
m = TextInput[1],
|
||||
s = TextInput[2],
|
||||
newHour = h.value,
|
||||
newMin = m.value,
|
||||
newSec = s.value,
|
||||
obj, objNew, objOld;
|
||||
index = index || 0;
|
||||
|
||||
if (newHour != timeOld[0]){
|
||||
obj = h;
|
||||
objNew = newHour;
|
||||
objOld = timeOld[0];
|
||||
}else if (newMin != timeOld[1]){
|
||||
obj = m;
|
||||
objNew = newMin;
|
||||
objOld = timeOld[1];
|
||||
}else if(newSec != timeOld[2]){
|
||||
obj = s;
|
||||
objNew = newSec;
|
||||
objOld = timeOld[2];
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
var duration = this.player.duration() || 0,
|
||||
durationSel;
|
||||
|
||||
var intRegex = /^\d+$/;//check if the objNew is an integer
|
||||
if(!intRegex.test(objNew) || objNew>60){
|
||||
objNew = objNew ==""?"":objOld;
|
||||
}
|
||||
|
||||
newHour = newHour == ""?0:newHour;
|
||||
newMin = newMin == ""?0:newMin;
|
||||
newSec = newSec == ""?0:newSec;
|
||||
|
||||
durationSel = videojs.TextTrack.prototype.parseCueTime(newHour+":"+newMin+":"+newSec);
|
||||
if (durationSel > duration){
|
||||
obj.value = objOld;
|
||||
obj.style.border = "1px solid red";
|
||||
}else{
|
||||
obj.value = objNew;
|
||||
h.style.border = m.style.border = s.style.border = "1px solid transparent";
|
||||
this.setValue(index,durationSel,false);
|
||||
|
||||
// Trigger slider change
|
||||
this._triggerSliderChange();
|
||||
}
|
||||
if (index===1){
|
||||
var oldTimeLeft = this.ctpl.el_.children,
|
||||
durationSelLeft = videojs.TextTrack.prototype.parseCueTime(oldTimeLeft[0].value+":"+oldTimeLeft[1].value+":"+oldTimeLeft[2].value);
|
||||
if (durationSel < durationSelLeft){
|
||||
obj.style.border = "1px solid red";
|
||||
}
|
||||
}else{
|
||||
|
||||
var oldTimeRight = this.ctpr.el_.children,
|
||||
durationSelRight = videojs.TextTrack.prototype.parseCueTime(oldTimeRight[0].value+":"+oldTimeRight[1].value+":"+oldTimeRight[2].value);
|
||||
if (durationSel > durationSelRight){
|
||||
obj.style.border = "1px solid red";
|
||||
}
|
||||
}
|
||||
},
|
||||
_triggerSliderChange: function(){
|
||||
this.player.trigger("sliderchange");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//----------------Public Functions----------------//
|
||||
|
||||
//-- Public Functions added to video-js
|
||||
|
||||
//Lock the Slider bar and it will not be possible to change the arrow positions
|
||||
videojs.Player.prototype.lockSlider = function(){
|
||||
return this.rangeslider.lock();
|
||||
};
|
||||
|
||||
//Unlock the Slider bar and it will be possible to change the arrow positions
|
||||
videojs.Player.prototype.unlockSlider = function(){
|
||||
return this.rangeslider.unlock();
|
||||
};
|
||||
|
||||
//Show the Slider Bar Component
|
||||
videojs.Player.prototype.showSlider = function(){
|
||||
return this.rangeslider.show();
|
||||
};
|
||||
|
||||
//Hide the Slider Bar Component
|
||||
videojs.Player.prototype.hideSlider = function(){
|
||||
return this.rangeslider.hide();
|
||||
};
|
||||
|
||||
//Show the Panel with the seconds of the selection
|
||||
videojs.Player.prototype.showSliderPanel = function(){
|
||||
return this.rangeslider.showPanel();
|
||||
};
|
||||
|
||||
//Hide the Panel with the seconds of the selection
|
||||
videojs.Player.prototype.hideSliderPanel = function(){
|
||||
return this.rangeslider.hidePanel();
|
||||
};
|
||||
|
||||
|
||||
//Show the control Time to edit the position of the arrows
|
||||
videojs.Player.prototype.showControlTime = function(){
|
||||
return this.rangeslider.showcontrolTime();
|
||||
};
|
||||
|
||||
//Hide the control Time to edit the position of the arrows
|
||||
videojs.Player.prototype.hideControlTime = function(){
|
||||
return this.rangeslider.hidecontrolTime();
|
||||
};
|
||||
|
||||
//Set a Value in second for both arrows
|
||||
videojs.Player.prototype.setValueSlider = function(start, end){
|
||||
return this.rangeslider.setValues(start, end);
|
||||
};
|
||||
|
||||
//The video will be played in a selected section
|
||||
videojs.Player.prototype.playBetween = function(start, end){
|
||||
return this.rangeslider.playBetween(start, end);
|
||||
};
|
||||
|
||||
//The video will loop between to values
|
||||
videojs.Player.prototype.loopBetween = function (start, end) {
|
||||
return this.rangeslider.loop(start, end);
|
||||
};
|
||||
|
||||
//Set a Value in second for the arrows
|
||||
videojs.Player.prototype.getValueSlider = function(){
|
||||
return this.rangeslider.getValues();
|
||||
};
|
||||
|
||||
|
||||
|
||||
//----------------Create new Components----------------//
|
||||
|
||||
//--Charge the new Component into videojs
|
||||
videojs.SeekBar.prototype.options_.children.RSTimeBar={}; //Range Slider Time Bar
|
||||
videojs.ControlBar.prototype.options_.children.ControlTimePanel={}; //Panel with the time of the range slider
|
||||
|
||||
|
||||
|
||||
//-- Design the new components
|
||||
|
||||
/**
|
||||
* Range Slider Time Bar
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.RSTimeBar = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.RSTimeBar.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.RSTimeBar.prototype.options_ = {
|
||||
children: {
|
||||
'SeekRSBar': {}
|
||||
}
|
||||
};
|
||||
|
||||
videojs.RSTimeBar.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-timebar-RS',
|
||||
innerHTML: ''
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Seek Range Slider Bar and holder for the selection bars
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.SeekRSBar = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.SeekRSBar.prototype.init_ =function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.SeekRSBar.prototype.options_ = {
|
||||
children: {
|
||||
'SelectionBar': {},
|
||||
'SelectionBarLeft': {},
|
||||
'SelectionBarRight': {},
|
||||
'TimePanel': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.SeekRSBar.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-rangeslider-holder'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
videojs.SeekRSBar.prototype.onMouseDown = function(event) {
|
||||
event.preventDefault();
|
||||
videojs.blockTextSelection();
|
||||
|
||||
if(!this.rs.options.locked) {
|
||||
videojs.on(document, "mousemove", videojs.bind(this,this.onMouseMove));
|
||||
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
|
||||
}
|
||||
};
|
||||
|
||||
videojs.SeekRSBar.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mousemove", this.onMouseMove, false);
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
};
|
||||
|
||||
videojs.SeekRSBar.prototype.onMouseMove = function(event) {
|
||||
var left = this.calculateDistance(event);
|
||||
|
||||
if (this.rs.left.pressed)
|
||||
this.setPosition(0,left);
|
||||
else if (this.rs.right.pressed)
|
||||
this.setPosition(1,left);
|
||||
|
||||
//Fix a problem with the presition in the display time
|
||||
var currentTimeDisplay = this.player_.controlBar.currentTimeDisplay.content;
|
||||
currentTimeDisplay.innerHTML = '<span class="vjs-control-text">Current Time </span>'+vjs.formatTime(this.rs._seconds(left), this.player_.duration());
|
||||
|
||||
// Trigger slider change
|
||||
if (this.rs.left.pressed||this.rs.right.pressed) {
|
||||
this.rs._triggerSliderChange();
|
||||
}
|
||||
};
|
||||
|
||||
videojs.SeekRSBar.prototype.setPosition = function(index,left,writeControlTime) {
|
||||
var writeControlTime = typeof writeControlTime!='undefined'?writeControlTime:true;
|
||||
//index = 0 for left side, index = 1 for right side
|
||||
var index = index || 0;
|
||||
|
||||
// Position shouldn't change when handle is locked
|
||||
if(this.rs.options.locked)
|
||||
return false;
|
||||
|
||||
// Check for invalid position
|
||||
if(isNaN(left))
|
||||
return false;
|
||||
|
||||
// Check index between 0 and 1
|
||||
if(!(index === 0 || index === 1))
|
||||
return false;
|
||||
|
||||
// Alias
|
||||
var ObjLeft = this.rs.left.el_,
|
||||
ObjRight = this.rs.right.el_,
|
||||
Obj = this.rs[index === 0 ? 'left' : 'right'].el_,
|
||||
tpr = this.rs.tpr.el_,
|
||||
tpl = this.rs.tpl.el_,
|
||||
bar = this.rs.bar,
|
||||
ctp = this.rs[index === 0 ? 'ctpl' : 'ctpr'].el_;
|
||||
|
||||
//Check if left arrow is passing the right arrow
|
||||
if ((index === 0 ?bar.updateLeft(left):bar.updateRight(left))){
|
||||
Obj.style.left = (left * 100) + '%';
|
||||
index === 0 ?bar.updateLeft(left):bar.updateRight(left);
|
||||
|
||||
this.rs[index === 0 ? 'start' : 'end'] = this.rs._seconds(left);
|
||||
|
||||
//Fix the problem when you press the button and the two arrow are underhand
|
||||
//left.zIndex = 10 and right.zIndex=20. This is always less in this case:
|
||||
if (index === 0){
|
||||
if((left) >= 0.9)
|
||||
ObjLeft.style.zIndex = 25;
|
||||
else
|
||||
ObjLeft.style.zIndex = 10;
|
||||
}
|
||||
|
||||
//-- Panel
|
||||
var TimeText = videojs.formatTime(this.rs._seconds(left)),
|
||||
tplTextLegth = tpl.children[0].innerHTML.length;
|
||||
var MaxP,MinP,MaxDisP;
|
||||
if (tplTextLegth<=4) //0:00
|
||||
MaxDisP = this.player_.isFullScreen?3.25:6.5;
|
||||
else if(tplTextLegth<=5)//00:00
|
||||
MaxDisP = this.player_.isFullScreen?4:8;
|
||||
else//0:00:00
|
||||
MaxDisP = this.player_.isFullScreen?5:10;
|
||||
if(TimeText.length<=4){ //0:00
|
||||
MaxP = this.player_.isFullScreen?97:93;
|
||||
MinP = this.player_.isFullScreen?0.1:0.5;
|
||||
}else if(TimeText.length<=5){//00:00
|
||||
MaxP = this.player_.isFullScreen?96:92;
|
||||
MinP = this.player_.isFullScreen?0.1:0.5;
|
||||
}else{//0:00:00
|
||||
MaxP = this.player_.isFullScreen?95:91;
|
||||
MinP = this.player_.isFullScreen?0.1:0.5;
|
||||
}
|
||||
|
||||
if (index===0){
|
||||
tpl.style.left = Math.max(MinP,Math.min(MaxP,(left * 100 - MaxDisP/2))) + '%';
|
||||
|
||||
if ((tpr.style.left.replace("%","") - tpl.style.left.replace("%",""))<=MaxDisP)
|
||||
tpl.style.left = Math.max(MinP,Math.min(MaxP,tpr.style.left.replace("%","")-MaxDisP)) + '%';
|
||||
tpl.children[0].innerHTML = TimeText;
|
||||
}else{
|
||||
tpr.style.left = Math.max(MinP,Math.min(MaxP,(left * 100 - MaxDisP/2))) + '%';
|
||||
|
||||
if (((tpr.style.left.replace("%","")||100) - tpl.style.left.replace("%",""))<=MaxDisP)
|
||||
tpr.style.left = Math.max(MinP,Math.min(MaxP,tpl.style.left.replace("%","")-0+MaxDisP)) + '%';
|
||||
tpr.children[0].innerHTML = TimeText;
|
||||
}
|
||||
//-- Control Time
|
||||
if(writeControlTime){
|
||||
var time = TimeText.split(":"),
|
||||
h,m,s;
|
||||
if(time.length == 2){
|
||||
h = 00;
|
||||
m = time[0];
|
||||
s = time[1];
|
||||
}else{
|
||||
h = time[0];
|
||||
m = time[1];
|
||||
s = time[2];
|
||||
}
|
||||
ctp.children[0].value = h;
|
||||
ctp.children[1].value = m;
|
||||
ctp.children[2].value = s;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
videojs.SeekRSBar.prototype.calculateDistance = function(event){
|
||||
var rstbX = this.getRSTBX();
|
||||
var rstbW = this.getRSTBWidth();
|
||||
var handleW = this.getWidth();
|
||||
|
||||
// Adjusted X and Width, so handle doesn't go outside the bar
|
||||
rstbX = rstbX + (handleW / 2);
|
||||
rstbW = rstbW - handleW;
|
||||
|
||||
// Percent that the click is through the adjusted area
|
||||
return Math.max(0, Math.min(1, (event.pageX - rstbX) / rstbW));
|
||||
};
|
||||
|
||||
videojs.SeekRSBar.prototype.getRSTBWidth = function() {
|
||||
return this.el_.offsetWidth;
|
||||
};
|
||||
videojs.SeekRSBar.prototype.getRSTBX = function() {
|
||||
return videojs.findPosition(this.el_).left;
|
||||
};
|
||||
videojs.SeekRSBar.prototype.getWidth = function() {
|
||||
return this.rs.left.el_.offsetWidth;//does not matter left or right
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is the bar with the selection of the RangeSlider
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.SelectionBar = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mouseup', this.onMouseUp);
|
||||
this.fired = false;
|
||||
}
|
||||
});
|
||||
|
||||
videojs.SelectionBar.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-selectionbar-RS'
|
||||
});
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype.onMouseUp = function(){
|
||||
var start = this.rs.left.el_.style.left.replace("%",""),
|
||||
end = this.rs.right.el_.style.left.replace("%",""),
|
||||
duration = this.player_.duration(),
|
||||
precision = this.rs.updatePrecision,
|
||||
segStart = videojs.round(start * duration/100, precision),
|
||||
segEnd = videojs.round(end * duration/100, precision);
|
||||
this.player_.currentTime(segStart);
|
||||
this.player_.play();
|
||||
this.rs.bar.activatePlay(segStart,segEnd);
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype.updateLeft = function(left) {
|
||||
var rightVal = this.rs.right.el_.style.left!=''?this.rs.right.el_.style.left:100;
|
||||
var right = parseFloat(rightVal) / 100;
|
||||
|
||||
var width = videojs.round((right - left),this.rs.updatePrecision); //round necessary for not get 0.6e-7 for example that it's not able for the html css width
|
||||
|
||||
//(right+0.00001) is to fix the precision of the css in html
|
||||
if(left <= (right+0.00001)) {
|
||||
this.rs.bar.el_.style.left = (left * 100) + '%';
|
||||
this.rs.bar.el_.style.width = (width * 100) + '%';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype.updateRight = function(right) {
|
||||
var leftVal = this.rs.left.el_.style.left!=''?this.rs.left.el_.style.left:0;
|
||||
var left = parseFloat(leftVal) / 100;
|
||||
|
||||
var width = videojs.round((right - left),this.rs.updatePrecision);//round necessary for not get 0.6e-7 for example that it's not able for the html css width
|
||||
|
||||
//(right+0.00001) is to fix the precision of the css in html
|
||||
if((right+0.00001) >= left) {
|
||||
this.rs.bar.el_.style.width = (width * 100) + '%';
|
||||
this.rs.bar.el_.style.left = ((right - width) * 100) + '%';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype.activatePlay = function(start,end){
|
||||
this.timeStart = start;
|
||||
this.timeEnd = end;
|
||||
|
||||
this.suspendPlay();
|
||||
|
||||
this.player_.on("timeupdate", videojs.bind(this,this._processPlay));
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype.suspendPlay = function(){
|
||||
this.fired = false;
|
||||
this.player_.off("timeupdate", videojs.bind(this,this._processPlay));
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype._processPlay = function (){
|
||||
//Check if current time is between start and end
|
||||
if(this.player_.currentTime() >= this.timeStart && (this.timeEnd < 0 || this.player_.currentTime() < this.timeEnd)){
|
||||
if(this.fired){ //Do nothing if start has already been called
|
||||
return;
|
||||
}
|
||||
this.fired = true; //Set fired flag to true
|
||||
}else{
|
||||
if(!this.fired){ //Do nothing if end has already been called
|
||||
return;
|
||||
}
|
||||
this.fired = false; //Set fired flat to false
|
||||
this.player_.pause(); //Call end function
|
||||
this.player_.currentTime(this.timeEnd);
|
||||
this.suspendPlay();
|
||||
}
|
||||
};
|
||||
|
||||
videojs.SelectionBar.prototype.process_loop = function () {
|
||||
var player = this.player;
|
||||
|
||||
if (player && this.looping) {
|
||||
var current_time = player.currentTime();
|
||||
|
||||
if (current_time < this.timeStart || this.timeEnd > 0 && this.timeEnd < current_time) {
|
||||
player.currentTime(this.timeStart);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the left arrow to select the RangeSlider
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.SelectionBarLeft = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
this.pressed = false;
|
||||
}
|
||||
});
|
||||
|
||||
videojs.SelectionBarLeft.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.SelectionBarLeft.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-rangeslider-handle vjs-selectionbar-left-RS',
|
||||
innerHTML: '<div class="vjs-selectionbar-arrow-RS"></div><div class="vjs-selectionbar-line-RS"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
videojs.SelectionBarLeft.prototype.onMouseDown = function(event) {
|
||||
event.preventDefault();
|
||||
videojs.blockTextSelection();
|
||||
if(!this.rs.options.locked) {
|
||||
this.pressed = true;
|
||||
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
|
||||
videojs.addClass(this.el_, 'active');
|
||||
}
|
||||
};
|
||||
|
||||
videojs.SelectionBarLeft.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
videojs.removeClass(this.el_, 'active');
|
||||
if(!this.rs.options.locked) {
|
||||
this.pressed = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is the right arrow to select the RangeSlider
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.SelectionBarRight = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('mousedown', this.onMouseDown);
|
||||
this.pressed = false;
|
||||
}
|
||||
});
|
||||
|
||||
videojs.SelectionBarRight.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.SelectionBarRight.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-rangeslider-handle vjs-selectionbar-right-RS',
|
||||
innerHTML: '<div class="vjs-selectionbar-arrow-RS"></div><div class="vjs-selectionbar-line-RS"></div>'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
videojs.SelectionBarRight.prototype.onMouseDown = function(event) {
|
||||
event.preventDefault();
|
||||
videojs.blockTextSelection();
|
||||
if(!this.rs.options.locked) {
|
||||
this.pressed = true;
|
||||
videojs.on(document, "mouseup", videojs.bind(this,this.onMouseUp));
|
||||
videojs.addClass(this.el_, 'active');
|
||||
}
|
||||
};
|
||||
|
||||
videojs.SelectionBarRight.prototype.onMouseUp = function(event) {
|
||||
videojs.off(document, "mouseup", this.onMouseUp, false);
|
||||
videojs.removeClass(this.el_, 'active');
|
||||
if(!this.rs.options.locked) {
|
||||
this.pressed = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is the time panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.TimePanel = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.TimePanel.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.TimePanel.prototype.options_ = {
|
||||
children: {
|
||||
'TimePanelLeft': {},
|
||||
'TimePanelRight': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.TimePanel.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-timepanel-RS'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is the left time panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.TimePanelLeft = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.TimePanelLeft.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.TimePanelLeft.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-timepanel-left-RS',
|
||||
innerHTML: '<span class="vjs-time-text">00:00</span>'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is the right time panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.TimePanelRight = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.TimePanelRight.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
videojs.TimePanelRight.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-timepanel-right-RS',
|
||||
innerHTML: '<span class="vjs-time-text">00:00</span>'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is the control time panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.ControlTimePanel= videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.ControlTimePanel.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
};
|
||||
|
||||
|
||||
videojs.ControlTimePanel.prototype.options_ = {
|
||||
children: {
|
||||
'ControlTimePanelLeft': {},
|
||||
'ControlTimePanelRight': {},
|
||||
}
|
||||
};
|
||||
|
||||
videojs.ControlTimePanel.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-controltimepanel-RS vjs-control',
|
||||
});
|
||||
};
|
||||
|
||||
videojs.ControlTimePanel.prototype.enable = function(enable){
|
||||
var enable = typeof enable != 'undefined'? enable:true;
|
||||
this.rs.ctpl.el_.children[0].disabled = enable?"":"disabled";
|
||||
this.rs.ctpl.el_.children[1].disabled = enable?"":"disabled";
|
||||
this.rs.ctpl.el_.children[2].disabled = enable?"":"disabled";
|
||||
this.rs.ctpr.el_.children[0].disabled = enable?"":"disabled";
|
||||
this.rs.ctpr.el_.children[1].disabled = enable?"":"disabled";
|
||||
this.rs.ctpr.el_.children[2].disabled = enable?"":"disabled";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is the control left time panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.ControlTimePanelLeft = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('keyup', this.onKeyUp);
|
||||
this.on('keydown', this.onKeyDown);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.ControlTimePanelLeft.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.timeOld = {};
|
||||
};
|
||||
|
||||
videojs.ControlTimePanelLeft.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-controltimepanel-left-RS',
|
||||
innerHTML: 'Start: <input type="text" id="controltimepanel" maxlength="2" value="00"/>:<input type="text" id="controltimepanel" maxlength="2" value="00"/>:<input type="text" id="controltimepanel" maxlength="2" value="00"/>'
|
||||
});
|
||||
};
|
||||
|
||||
videojs.ControlTimePanelLeft.prototype.onKeyDown = function(event) {
|
||||
this.timeOld[0] = this.el_.children[0].value;
|
||||
this.timeOld[1] = this.el_.children[1].value;
|
||||
this.timeOld[2] = this.el_.children[2].value;
|
||||
};
|
||||
|
||||
videojs.ControlTimePanelLeft.prototype.onKeyUp = function(event) {
|
||||
this.rs._checkControlTime(0,this.el_.children,this.timeOld);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is the control right time panel
|
||||
* @param {videojs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
videojs.ControlTimePanelRight = videojs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
videojs.Component.call(this, player, options);
|
||||
this.on('keyup', this.onKeyUp);
|
||||
this.on('keydown', this.onKeyDown);
|
||||
}
|
||||
});
|
||||
|
||||
videojs.ControlTimePanelRight.prototype.init_ = function(){
|
||||
this.rs = this.player_.rangeslider;
|
||||
this.timeOld = {};
|
||||
};
|
||||
|
||||
videojs.ControlTimePanelRight.prototype.createEl = function(){
|
||||
return videojs.Component.prototype.createEl.call(this, 'div', {
|
||||
className: 'vjs-controltimepanel-right-RS',
|
||||
innerHTML: 'End: <input type="text" id="controltimepanel" maxlength="2" value="00"/>:<input type="text" id="controltimepanel" maxlength="2" value="00"/>:<input type="text" id="controltimepanel" maxlength="2" value="00"/>'
|
||||
});
|
||||
};
|
||||
|
||||
videojs.ControlTimePanelRight.prototype.onKeyDown = function(event) {
|
||||
this.timeOld[0] = this.el_.children[0].value;
|
||||
this.timeOld[1] = this.el_.children[1].value;
|
||||
this.timeOld[2] = this.el_.children[2].value;
|
||||
};
|
||||
|
||||
videojs.ControlTimePanelRight.prototype.onKeyUp = function(event) {
|
||||
this.rs._checkControlTime(1,this.el_.children,this.timeOld);
|
||||
};
|
||||
})();
|
||||
110
common/static/js/vendor/ova/reply-annotator.js
vendored
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
Reply Annotator Plugin v1.0 (https://github.com/danielcebrian/reply-annotator)
|
||||
Copyright (C) 2014 Daniel Cebrian Robles
|
||||
License: https://github.com/danielcebrian/reply-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.
|
||||
*/
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var _ref,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Reply = (function(_super) {
|
||||
__extends(Reply, _super);
|
||||
|
||||
function Reply() {
|
||||
this.pluginSubmit = __bind(this.pluginSubmit, this);
|
||||
this.updateField = __bind(this.updateField, this);
|
||||
_ref = Reply.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
Reply.prototype.field = null;
|
||||
|
||||
Reply.prototype.input = null;
|
||||
|
||||
Reply.prototype.pluginInit = function() {
|
||||
console.log("Reply-pluginInit");
|
||||
//Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//-- Editor
|
||||
this.field = this.annotator.editor.addField({
|
||||
type: 'input', //options (textarea,input,select,checkbox)
|
||||
load: this.updateField,
|
||||
submit: this.pluginSubmit,
|
||||
});
|
||||
var newfield = Annotator.$('<li class="annotator-item reply-item" style="display:none"><span class="parent-annotation">0</span></li>');//reply-item is the parent value
|
||||
Annotator.$(this.field).replaceWith(newfield);
|
||||
this.field=newfield[0];
|
||||
|
||||
//-- Viewer
|
||||
var newview = this.annotator.viewer.addField({
|
||||
load: this.updateViewer,
|
||||
});
|
||||
|
||||
return this.input = $(this.field).find(':input');
|
||||
};
|
||||
|
||||
// New JSON for the database
|
||||
Reply.prototype.pluginSubmit = function(field, annotation) {
|
||||
// since each annotation has their own reply item, this "find" is element specific
|
||||
var replyItem = $(this.annotator.editor.element).find(".reply-item span.parent-annotation");
|
||||
// checks to see if the current annotation is a reply by checking parent numbers
|
||||
var parent = replyItem.html() !== '' ? replyItem.html() : '0';
|
||||
// if the parent number is not empty or zero, we know that this is a comment
|
||||
if (parent !== '0') {
|
||||
annotation.media = 'comment';
|
||||
}
|
||||
|
||||
// apparently some browsers continue adding <font> tags here for nonreplies
|
||||
// this will check and set to 0 (nonreply) if it fails
|
||||
if (parseInt(parent, 10) === NaN){
|
||||
parent = '0';
|
||||
}
|
||||
|
||||
// set 0, because it is not a reply
|
||||
annotation.parent = parent;
|
||||
return annotation.parent;
|
||||
};
|
||||
|
||||
|
||||
Reply.prototype.updateViewer = function(field, annotation) {
|
||||
var self = this,
|
||||
field = $(field),
|
||||
ret = field.addClass('reply-viewer-annotator').html(function() {
|
||||
var string;
|
||||
return self;
|
||||
});
|
||||
field.remove();
|
||||
this.annotation = annotation;
|
||||
//Create the actions for the buttons
|
||||
return ret;
|
||||
};
|
||||
|
||||
Reply.prototype.updateField = function(field, annotation) {
|
||||
//reset parent value
|
||||
var replyItem = $(this.annotator.editor.element).find(".reply-item span.parent-annotation");
|
||||
return replyItem.html('0');
|
||||
};
|
||||
|
||||
return Reply;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
|
||||
186
common/static/js/vendor/ova/richText-annotator.js
vendored
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
Rich Text Annotator Plugin v1.0 (https://github.com/danielcebrian/richText-annotator)
|
||||
Copyright (C) 2014 Daniel Cebrian Robles
|
||||
License: https://github.com/danielcebrian/richText-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.
|
||||
*/
|
||||
var _ref,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.RichText = (function(_super) {
|
||||
|
||||
__extends(RichText, _super);
|
||||
|
||||
|
||||
//Default tinymce configuration
|
||||
RichText.prototype.options = {
|
||||
tinymce:{
|
||||
selector: "li.annotator-item textarea",
|
||||
skin: 'studio-tmce4',
|
||||
formats: {
|
||||
code: {
|
||||
inline: 'code'
|
||||
}
|
||||
},
|
||||
codemirror: {
|
||||
path: "/static/js/vendor"
|
||||
},
|
||||
plugins: "image link codemirror media",
|
||||
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 | link image media | code ",
|
||||
resize: "both",
|
||||
}
|
||||
};
|
||||
|
||||
function RichText(element,options) {
|
||||
_ref = RichText.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
};
|
||||
|
||||
|
||||
RichText.prototype.pluginInit = function() {
|
||||
console.log("RichText-pluginInit");
|
||||
var annotator = this.annotator,
|
||||
editor = this.annotator.editor;
|
||||
// check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// editor Setup
|
||||
annotator.editor.addField({
|
||||
type: 'input',
|
||||
submit: this.submitEditor,
|
||||
load: this.updateEditor,
|
||||
});
|
||||
|
||||
// viewer setup
|
||||
annotator.viewer.addField({
|
||||
load: this.updateViewer,
|
||||
});
|
||||
|
||||
// makes sure that tinymce is hidden and shown along with the editor
|
||||
annotator.subscribe("annotationEditorShown", function() {
|
||||
$(annotator.editor.element).find('.mce-tinymce')[0].style.display = 'block';
|
||||
annotator.editor.checkOrientation();
|
||||
});
|
||||
annotator.subscribe("annotationEditorHidden", function() {
|
||||
$(annotator.editor.element).find('.mce-tinymce')[0].style.display = 'none';
|
||||
});
|
||||
|
||||
// set listener for tinymce;
|
||||
this.options.tinymce.setup = function(ed) {
|
||||
|
||||
// note that the following does not work in Firefox, fix using submitEditor function
|
||||
ed.on('change', function(e) {
|
||||
// set the modification in the textarea of annotator
|
||||
$(editor.element).find('textarea')[0].value = tinymce.activeEditor.getContent();
|
||||
});
|
||||
|
||||
// creates a function called whenever editor is resized
|
||||
ed.on('init', function(mceInstance) {
|
||||
|
||||
// get win means this event activates when window is resized
|
||||
tinymce.dom.Event.bind(ed.getWin(), 'resize', function(e){
|
||||
|
||||
// mceInstance.target gets the editor, its id is used to retrieved iframe
|
||||
$("#"+mceInstance.target.id+"_ifr").css('min-width', '400px');
|
||||
});
|
||||
});
|
||||
// new button to add Rubrics of the url https://gteavirtual.org/rubric
|
||||
ed.addButton('rubric', {
|
||||
icon: 'rubric',
|
||||
title : 'Insert a rubric',
|
||||
onclick: function() {
|
||||
ed.windowManager.open({
|
||||
title: 'Insert a public rubric of the website https://gteavirtual.org/rubric',
|
||||
body: [
|
||||
{type: 'textbox', name: 'url', label: 'Url'}
|
||||
],
|
||||
onsubmit: function(e) {
|
||||
// Insert content when the window form is submitted
|
||||
var url = e.data.url;
|
||||
var name = 'irb';
|
||||
var irb;
|
||||
// get the variable 'name' from the given url
|
||||
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
|
||||
var results = regex.exec(url);
|
||||
|
||||
// the rubric id
|
||||
irb = results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
if (irb==''){
|
||||
ed.windowManager.alert('Error: The given webpage didn\'t have a irb variable in the url');
|
||||
}else{
|
||||
var iframeRubric = "<iframe src='https://gteavirtual.org/rubric/?mod=portal&scr=viewrb&evt=frame&irb=" + irb + "' style='width:800px;height:600px;overflow-y: scroll;background:transparent' frameborder='0' ></iframe>";
|
||||
ed.setContent(ed.getContent()+iframeRubric);
|
||||
$(editor.element).find('textarea')[0].value = ed.getContent();
|
||||
}
|
||||
}
|
||||
});
|
||||
ed.insertContent('Main button');
|
||||
ed.label = 'My Button';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// makes sure that if tinymce exists already that this removes/destroys previous version
|
||||
if (tinymce.editors.length > 0) {
|
||||
tinymce.remove("li.annotator-item textarea");
|
||||
}
|
||||
tinymce.init(this.options.tinymce);
|
||||
};
|
||||
|
||||
/**
|
||||
* Copies the content of annotation text and inserts it into the tinymce instance
|
||||
*/
|
||||
RichText.prototype.updateEditor = function(field, annotation) {
|
||||
var text = typeof annotation.text != 'undefined' ? annotation.text : '';
|
||||
tinymce.activeEditor.setContent(text);
|
||||
$(field).remove(); // this is the auto create field by annotator and it is not necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the text from the annotation text and makes sure it replaces the old text field
|
||||
* with the richtext from tinymce.
|
||||
*/
|
||||
RichText.prototype.updateViewer = function(field, annotation) {
|
||||
var textDiv = $(field.parentNode).find('div:first-of-type')[0];
|
||||
textDiv.innerHTML = annotation.text;
|
||||
$(textDiv).addClass('richText-annotation');
|
||||
$(field).remove(); // this is the auto create field by annotator and it is not necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called before submission. It checks to make sure tinymce content is saved
|
||||
*/
|
||||
RichText.prototype.submitEditor = function(field, annotation) {
|
||||
var tinymceText = tinymce.activeEditor.getContent();
|
||||
|
||||
// Firefox has an issue where the text is not saved ("on" function doesn't work).
|
||||
// this helps save it anyway.
|
||||
if (annotation.text !== tinymceText) {
|
||||
annotation.text = tinymce.activeEditor.getContent();
|
||||
}
|
||||
}
|
||||
|
||||
return RichText;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
684
common/static/js/vendor/ova/share-annotator.js
vendored
@@ -1,684 +0,0 @@
|
||||
/*
|
||||
Share Annotation Plugin v1.1 (https://github.com/danielcebrian/share-annotator)
|
||||
Copyright (C) 2014 Daniel Cebrian Robles
|
||||
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.
|
||||
*/
|
||||
var _ref,
|
||||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
||||
|
||||
Annotator.Plugin.Share = (function(_super) {
|
||||
__extends(Share, _super);
|
||||
|
||||
// Default Share configuration
|
||||
Share.prototype.options = {
|
||||
shareIn: ['facebook', 'twitter', 'email', 'google'],
|
||||
getUrl: {
|
||||
'facebook': function(title, link, noteText) {
|
||||
return 'https://www.facebook.com/sharer/sharer.php?s=100&p[url]=' + link + '&p[title]=' + encodeURIComponent('Open Video Annotation') + '&p[summary]=' + noteText;
|
||||
},
|
||||
'twitter': function(title, link, noteText) {
|
||||
return 'https://twitter.com/intent/tweet?original_referer=' + link + '&source=tweetbutton&url=' + link + "&via=OpenVideoAnnotation&text=" + encodeURIComponent('I want to share the following Open Video Annotation: ');
|
||||
},
|
||||
'google': function(title, link, noteText) {
|
||||
return 'https://plus.google.com/share?url=' + link;
|
||||
},
|
||||
'email': function(title, link, noteText){
|
||||
return 'mailto:?subject=' + title + '&body=' + link;
|
||||
}
|
||||
},
|
||||
baseUrl: '', // baseUrl = the base url for all the shared annotations
|
||||
};
|
||||
|
||||
function Share(element, options) {
|
||||
if (typeof options !== 'undefined') {
|
||||
this.options.shareIn = typeof options.shareIn !== 'undefined' ? options.shareIn : this.options.shareIn;
|
||||
}
|
||||
this.buildHTMLShareButton = __bind(this.buildHTMLShareButton, this);
|
||||
this.runningAPI = __bind(this.runningAPI, this);
|
||||
this.updateViewer = __bind(this.updateViewer, this);
|
||||
_ref = Share.__super__.constructor.apply(this, arguments);
|
||||
return _ref;
|
||||
}
|
||||
|
||||
Share.prototype.field = null;
|
||||
|
||||
Share.prototype.input = null;
|
||||
|
||||
Share.prototype.pluginInit = function() {
|
||||
// Check that annotator is working
|
||||
if (!Annotator.supported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// -- Editor
|
||||
this.field = this.annotator.editor.addField({
|
||||
type: 'input', // options (textarea, input, select, checkbox)
|
||||
});
|
||||
|
||||
// Modify the element created with annotator to be an invisible span
|
||||
var newfield = Annotator.$('<li class="annotator-item">' + this.buildHTMLShareButton('Share without saving:') + '</li>');
|
||||
Annotator.$(this.field).replaceWith(newfield);
|
||||
this.field=newfield[0];
|
||||
// Create the actions for the buttons
|
||||
this.buttonsActions(this.field, 2, this.options.baseUrl); // 2 is the method of the API that will be for share without saving
|
||||
|
||||
// Init the API plugin
|
||||
var APIoptions = this.initAPI();
|
||||
|
||||
this.runAPI(APIoptions);
|
||||
|
||||
// -- Viewer
|
||||
var newview = this.annotator.viewer.addField({
|
||||
load: this.updateViewer,
|
||||
});
|
||||
|
||||
return this.input = $(this.field).find(':input');
|
||||
};
|
||||
|
||||
// Share button HTML
|
||||
Share.prototype.buildHTMLShareButton = function(title, id) {
|
||||
var title = title || '';
|
||||
var id = typeof id !== 'undefined' ? 'annotationId="' + id + '"' : '';
|
||||
var titleText = title !== '' ? '<div class="share-text-annotator">' + title + '</div>' : '';
|
||||
var shareButton = '<div class="share-button-annotator share-button" ' + id + '></div>';
|
||||
var popup = '<div class="share-popup-overlay-bg" style="z-index:30000000000"><div class="share-popup"><div class="share-popup-items"></div><div class="close-btn">Close</div></div></div>';
|
||||
// checks to make sure that no popup overlay already exists (though hidden) and creates a new one if it does not exist
|
||||
if ($('.share-popup-overlay-bg').length === 0) {
|
||||
$('.annotator-wrapper').append(popup);
|
||||
}
|
||||
return '<div class="share-container-annotator">' + titleText + shareButton + '</div>';
|
||||
}
|
||||
|
||||
// template for the design of the Share Plugin
|
||||
Share.prototype.buildHTMLPopup = function(title) {
|
||||
var buttons = '';
|
||||
if (typeof this.options.shareIn !== 'undefined'){
|
||||
this.options.shareIn.forEach(function(item) {
|
||||
buttons += '<div class="share-' + item + '-annotator share-button">' + item.charAt(0).toUpperCase() + item.slice(1) + '</div>';
|
||||
});
|
||||
}
|
||||
this.uri = (typeof this.uri !== 'undefined') ? this.uri : '';
|
||||
var title = '<div class="share-popup-title">' + title.replace(":", "") + '</div>';
|
||||
var copy = '<div class="share-popup-copy">Copy and Share:</div>';
|
||||
var uri = '<input type="text" class="share-popup-uri" onclick="javascript:this.select();" readonly="true" value="' + this.uri + '">';
|
||||
var popup = title + buttons + copy + uri;
|
||||
return popup;
|
||||
}
|
||||
|
||||
// Create the actions for the buttons
|
||||
Share.prototype.buttonsActions = function(field, method, url) {
|
||||
var share = this;
|
||||
|
||||
// hide popup when user clicks on close button
|
||||
$('.close-btn').click(function() {
|
||||
$('.share-popup-overlay-bg').hide();
|
||||
});
|
||||
// hides the popup if user clicks anywhere outside the container
|
||||
$('.share-popup-overlay-bg').click(function() {
|
||||
$('.share-popup-overlay-bg').hide();
|
||||
});
|
||||
// prevents the overlay from closing if user clicks inside the popup overlay
|
||||
$('.share-popup').click(function() {
|
||||
return false;
|
||||
});
|
||||
// Share button
|
||||
$(field).find('.share-button-annotator.share-button').click(function(event) {
|
||||
event.preventDefault(); // disable normal link function so that it doesn't refresh the page
|
||||
var _field = this;
|
||||
var ovaId = $(this).attr('annotationId');
|
||||
var title = method === 1 ? 'Share' : 'Share without saving';
|
||||
|
||||
// share.uri will be useful for buildHTMLPopup functions
|
||||
share.uri = share.createAPIURL(method, ovaId, url);
|
||||
|
||||
// display your popup
|
||||
$('.share-popup-overlay-bg').show();
|
||||
|
||||
// build buttons
|
||||
$('.share-popup-items').html(share.buildHTMLPopup(title));
|
||||
|
||||
// buttons actions
|
||||
if (typeof share.options.shareIn !== 'undefined') {
|
||||
share.options.shareIn.forEach(function(item) {
|
||||
$('.share-' + item + '-annotator.share-button').click(function() {
|
||||
var url = share.createAPIURL(method, ovaId, url);
|
||||
var title = "Sharing a annotation with Open Video Annotation";
|
||||
var link = encodeURIComponent(url);
|
||||
var noteText = share.getSource('ovaText');
|
||||
var finalUrl = '';
|
||||
if (method === 1) {
|
||||
var viewer = share.annotator.viewer;
|
||||
var textarea = $(viewer.element).find('div:first').html();
|
||||
noteText = encodeURIComponent(textarea);
|
||||
}
|
||||
finalUrl = typeof share.options.getUrl[item] !== 'undefined' ? share.options.getUrl[item](title, link, noteText) : '';
|
||||
if (typeof share.options.getUrl[item] !== 'undefined') {
|
||||
window.open(finalUrl);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Share.prototype.createAPIURL = function(method, ovaId, url) {
|
||||
var annotator = this.annotator;
|
||||
var editor = annotator.editor;
|
||||
var method = method || 1;
|
||||
var url = url || window.location.href;
|
||||
|
||||
url += (url.indexOf('?') >= 0) ? '&' : '?';
|
||||
|
||||
if (method === 1) {
|
||||
var ovaId = (typeof ovaId !== 'undefined') ? ovaId : '';
|
||||
url += 'ovaId=' + ovaId;
|
||||
} else if (method === 2) {
|
||||
var ovaText = this.getSource('ovaText') || " ";
|
||||
url += 'ovaText=' + ovaText;
|
||||
if (typeof editor.VideoJS !== 'undefined' && editor.VideoJS !== -1) { // Video Annotation
|
||||
var ovaStart = this.getSource('ovaStart') || " ";
|
||||
var ovaEnd = this.getSource('ovaEnd') || " ";
|
||||
var ovaContainer = this.getSource('ovaContainer') || " ";
|
||||
var ovaSrc = this.getSource('ovaSrc') || " ";
|
||||
url += '&ovaStart=' + ovaStart
|
||||
+ '&ovaEnd=' + ovaEnd
|
||||
+ '&ovaContainer=' + ovaContainer
|
||||
+ '&ovaSrc=' + ovaSrc;
|
||||
} else if (typeof editor.OpenSeaDragon !== 'undefined' && editor.OpenSeaDragon !== -1) { // Image Annotation
|
||||
var ovaLeft = this.getSource('ovaLeft') || " ";
|
||||
var ovaTop = this.getSource('ovaTop') || " ";
|
||||
var ovaWidth = this.getSource('ovaWidth') || " ";
|
||||
var ovaHeight = this.getSource('ovaHeight') || " ";
|
||||
var ovaLeftZoom = this.getSource('ovaLeftZoom') || " ";
|
||||
var ovaTopZoom = this.getSource('ovaTopZoom') || " ";
|
||||
var ovaWidthZoom = this.getSource('ovaWidthZoom') || " ";
|
||||
var ovaHeightZoom = this.getSource('ovaHeightZoom') || " ";
|
||||
var ovaContainer = this.getSource('ovaContainer') || " ";
|
||||
var ovaSrc = this.getSource('ovaSrc') || " ";
|
||||
url += '&ovaLeft=' + ovaLeft
|
||||
+ '&ovaTop=' + ovaTop
|
||||
+ '&ovaWidth=' + ovaWidth
|
||||
+ '&ovaHeight=' + ovaHeight
|
||||
+ '&ovaLeftZoom=' + ovaLeftZoom
|
||||
+ '&ovaTopZoom=' + ovaTopZoom
|
||||
+ '&ovaWidthZoom=' + ovaWidthZoom
|
||||
+ '&ovaHeightZoom=' + ovaHeightZoom
|
||||
+ '&ovaContainer=' + ovaContainer
|
||||
+ '&ovaSrc=' + ovaSrc;
|
||||
} else { // Text Annotation
|
||||
var ovaStart = this.getSource('ovaStart') || " ";
|
||||
var ovaEnd = this.getSource('ovaEnd') || " ";
|
||||
var ovastartOffset = this.getSource('ovastartOffset') || " ";
|
||||
var ovaendOffset = this.getSource('ovaendOffset') || " ";
|
||||
url += '&ovaStart=' + ovaStart
|
||||
+ '&ovaEnd=' + ovaEnd
|
||||
+ '&ovastartOffset=' + ovastartOffset
|
||||
+ '&ovaendOffset=' + ovaendOffset;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
Share.prototype.getSource = function(source) {
|
||||
var source = source || '';
|
||||
if (source === 'ovaId') { // method 1
|
||||
source = this.annotation.id;
|
||||
} else { // method 2
|
||||
var annotator = this.annotator;
|
||||
var editor = annotator.editor;
|
||||
var textarea = $(editor.element).find('textarea')[0];
|
||||
|
||||
if (source === 'ovaText') {
|
||||
source = textarea.value;
|
||||
}
|
||||
|
||||
if (typeof editor.VideoJS !== 'undefined' && editor.VideoJS !== -1) { // Video Annotation
|
||||
if (source === 'ovaContainer') {
|
||||
source = editor.VideoJS;
|
||||
}
|
||||
else if (source === 'ovaSrc') {
|
||||
source = annotator.mplayer[editor.VideoJS].tech.options_.source.src;
|
||||
} else if (source === 'ovaStart') {
|
||||
source = annotator.mplayer[editor.VideoJS].rangeslider.getValues().start;
|
||||
} else if (source === 'ovaEnd') {
|
||||
source = annotator.mplayer[editor.VideoJS].rangeslider.getValues().end;
|
||||
}
|
||||
} else if (typeof editor.OpenSeaDragon !== 'undefined' && editor.OpenSeaDragon !== -1) { // Image Annotation
|
||||
var annotation = editor.annotation;
|
||||
if (source === 'ovaLeft') {
|
||||
source = annotator.osda.rectPosition ? annotator.osda.rectPosition.left : annotation.rangePosition.left;
|
||||
} else if (source === 'ovaTop') {
|
||||
source = annotator.osda.rectPosition ? annotator.osda.rectPosition.top : annotation.rangePosition.top;
|
||||
} else if (source === 'ovaWidth') {
|
||||
source = annotator.osda.rectPosition ? annotator.osda.rectPosition.width : annotation.rangePosition.width;
|
||||
} else if (source ==='ovaHeight') {
|
||||
source = annotator.osda.rectPosition ? annotator.osda.rectPosition.height : annotation.rangePosition.height;
|
||||
} else if (source === 'ovaLeftZoom') {
|
||||
source = annotator.osda.viewer.drawer.viewport.getBounds().x;
|
||||
} else if (source === 'ovaTopZoom') {
|
||||
source = annotator.osda.viewer.drawer.viewport.getBounds().y;
|
||||
} else if (source === 'ovaWidthZoom') {
|
||||
source = annotator.osda.viewer.drawer.viewport.getBounds().width;
|
||||
} else if (source === 'ovaHeightZoom') {
|
||||
source = annotator.osda.viewer.drawer.viewport.getBounds().height;
|
||||
} else if (source === 'ovaContainer') {
|
||||
source = annotator.osda.viewer.id;
|
||||
} else if (source === 'ovaSrc') {
|
||||
var source = annotator.osda.viewer.source;
|
||||
var tilesUrl = typeof source.tilesUrl !== 'undefined' ? source.tilesUrl : '';
|
||||
var functionUrl = typeof source.getTileUrl !== 'undefined' ? source.getTileUrl : '';
|
||||
source = tilesUrl !== '' ? tilesUrl : ('' + functionUrl).replace(/\s+/g, ' '); // - target.src (media source)
|
||||
}
|
||||
} else { // Text Annotation
|
||||
var annotation = editor.annotation;
|
||||
// if ranges is 0 then it is a comment
|
||||
if (annotation.ranges.length > 0) {
|
||||
if(source === 'ovastartOffset') {
|
||||
source = annotation.ranges[0].startOffset;
|
||||
} else if (source === 'ovaendOffset') {
|
||||
source = annotation.ranges[0].endOffset;
|
||||
} else if (source === 'ovaStart') {
|
||||
source = annotation.ranges[0].start;
|
||||
} else if (source === 'ovaEnd') {
|
||||
source = annotation.ranges[0].end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return encodeURIComponent(source);
|
||||
};
|
||||
|
||||
Share.prototype.initAPI = function() {
|
||||
// -- Detect API in the URL -- //
|
||||
/*
|
||||
The first option is to give a known id of an annotation
|
||||
Example http:// url.com/#id=rTcpOjIMT2aF1apDtboC-Q
|
||||
*/
|
||||
var API = {};
|
||||
var ovaId = this.getParameterByName('ovaId'); // Method 1 (Obligatory)
|
||||
var start = this.getParameterByName('ovaStart'); // Method 2 (Obligatory)
|
||||
var end = this.getParameterByName('ovaEnd'); // Method 2 (Obligatory)
|
||||
var container = this.getParameterByName('ovaContainer'); // Method 2 (Obligatory)
|
||||
var src = this.getParameterByName('ovaSrc'); // Method 2 (Obligatory)
|
||||
var text = this.getParameterByName('ovaText'); // Method 2
|
||||
var user = this.getParameterByName('ovaUser'); // Method 2
|
||||
var Left = this.getParameterByName('ovaLeft'); // Method 2
|
||||
var Top = this.getParameterByName('ovaTop'); // Method 2
|
||||
var Width = this.getParameterByName('ovaWidth'); // Method 2
|
||||
var Height = this.getParameterByName('ovaHeight'); // Method 2
|
||||
var leftZoom = this.getParameterByName('ovaLeftZoom'); // Method 2
|
||||
var topZoom = this.getParameterByName('ovaTopZoom'); // Method 2
|
||||
var widthZoom = this.getParameterByName('ovaWidthZoom'); // Method 2
|
||||
var heightZoom = this.getParameterByName('ovaHeightZoom'); // Method 2
|
||||
var startOffset = this.getParameterByName('ovastartOffset'); // Method 2
|
||||
var endOffset = this.getParameterByName('ovaendOffset'); // Method 2
|
||||
|
||||
// remove the variables from the url browser
|
||||
var stripped_url = top.location.href;
|
||||
if (ovaId !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaId');
|
||||
if (start !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaStart');
|
||||
if (end !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaEnd');
|
||||
if (container !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaContainer');
|
||||
if (src !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaSrc');
|
||||
if (text !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaText');
|
||||
if (user !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaUser');
|
||||
if (Left !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaLeft');
|
||||
if (Top !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaTop');
|
||||
if (Width !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaWidth');
|
||||
if (Height !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaHeight');
|
||||
if (leftZoom !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaLeftZoom');
|
||||
if (topZoom !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaTopZoom');
|
||||
if (widthZoom !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaWidthZoom');
|
||||
if (heightZoom !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaHeightZoom');
|
||||
if (startOffset !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovastartOffset');
|
||||
if (endOffset !== '') stripped_url = this.removeVariableFromURL(stripped_url, 'ovaendOffset');
|
||||
window.history.pushState("object or string", "Title", stripped_url);
|
||||
|
||||
|
||||
// Method 1 API with the Id of the annotation
|
||||
// Example: http://danielcebrian.com/annotations/demo.html?&ovaId=wtva_SjnQb2HtqppDihKug
|
||||
if (ovaId !== '') {
|
||||
$.extend(API, {method: 1, ovaId: ovaId});
|
||||
}
|
||||
// Method 2 API with all the parameter to load the annotation
|
||||
// Example with video: http://danielcebrian.com/annotations/demo.html?ovaContainer=vid1&ovaSrc=http%3A%2F%2Fvideo-js.zencoder.com%2Foceans-clip.mp4&ovaStart=2&ovaEnd=10&ovaText=This%20is%20test&ovaUser=Test%20User
|
||||
// Example with text: http://danielcebrian.com/annotations/demo.html?ovaStart=%2Fp%5B1%5D&ovaEnd=%2Fp%5B1%5D&ovastartOffset=542&ovaendOffset=572&ovaText=API
|
||||
|
||||
if (start !== '' && end !== '' && container !== '' && src !== '') { // video api
|
||||
$.extend(API, {method: 2, start: start, end: end, container: container, src: src, text: text, user: user});
|
||||
} else if (Left !== '' && Top !== '' && Width !== '' && Height !== '' && leftZoom !== '' && topZoom !== '' && widthZoom !== '' && heightZoom !== '') { // image api
|
||||
$.extend(API, {method: 2, Left: Left, Top: Top, Width: Width, Height: Height, leftZoom: leftZoom, topZoom: topZoom, widthZoom: widthZoom, heightZoom: heightZoom, container: container, src: src, text: text, user: user});
|
||||
} else if (start !== '' && end !== '' && startOffset !== '' && endOffset !== '') { // text api
|
||||
$.extend(API, {method: 2, start: start, end: end, startOffset: startOffset, endOffset: endOffset, text: text, user: user});
|
||||
}
|
||||
return API;
|
||||
}
|
||||
Share.prototype.runningAPI = function (annotations, API) {
|
||||
var wrapper = $('.annotator-wrapper').parent()[0];
|
||||
var mplayer;
|
||||
var osda;
|
||||
var self = this;
|
||||
|
||||
// Set Annotator in wrapper to fix quick DOM
|
||||
$.data(wrapper, 'annotator', self.annotator);// Set the object in the span
|
||||
annotator = window.annotator = $.data(wrapper, 'annotator');
|
||||
mplayer = (typeof annotator.mplayer !== 'undefined') ? annotator.mplayer : [];
|
||||
osda = (typeof annotator.osda !== 'undefined') ? annotator.osda : [];
|
||||
|
||||
// Detect if the URL has an API element
|
||||
if (typeof API !== 'undefined' && typeof API.method !== 'undefined' && (parseInt(API.method, 10) === 1 || parseInt(API.method, 10) === 2)) {
|
||||
if (parseInt(API.method, 10) === 1) {
|
||||
var allannotations = annotator.plugins['Store'].annotations;
|
||||
var ovaId = parseInt(decodeURIComponent(API.ovaId), 10);
|
||||
|
||||
for (var item in allannotations) {
|
||||
var an = allannotations[item];
|
||||
var olditem;
|
||||
if (typeof an.id !== 'undefined' && parseInt(an.id, 10) === ovaId) { // this is the annotation
|
||||
if (self._isVideo(an)) {// It is a video
|
||||
if (typeof mplayer[an.target.container] !== 'undefined') {
|
||||
var player = mplayer[an.target.container];
|
||||
if (player.id_ === an.target.container) {
|
||||
var anFound = an;
|
||||
videojs(player.id_).ready(function() {
|
||||
if (player.techName !== 'Youtube') {
|
||||
player.preload('auto');
|
||||
}
|
||||
player.autoPlayAPI = anFound;
|
||||
player.play();
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (an.media === "image") { // It is a OpenSeaDragon Annotation
|
||||
if ($("div#" + an.target.container).length) {
|
||||
var isOpenViewer = typeof annotator.osda !== "undefined" && typeof annotator.osda.viewer !== "undefined";
|
||||
function waitingOsda(){
|
||||
isOpenViewer = typeof annotator.osda !== "undefined" && typeof annotator.osda.viewer !== "undefined";
|
||||
if (typeof olditem === "undefined") {
|
||||
olditem = item;
|
||||
}
|
||||
if (!isOpenViewer) {
|
||||
setTimeout(waitingOsda, 200);
|
||||
} else {
|
||||
an = allannotations[olditem];
|
||||
$(an.highlights).parent().find('.annotator-hl').removeClass('api');
|
||||
// change the color
|
||||
$(an.highlights).addClass('api');
|
||||
// change zoom
|
||||
if (typeof annotator !== 'undefined' && typeof annotator.osda !== 'undefined') {
|
||||
var currentBounds = annotator.osda.viewer.drawer.viewport.getBounds();
|
||||
var bounds = typeof an.bounds !== 'undefined' ? an.bounds : {};
|
||||
|
||||
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;
|
||||
}
|
||||
annotator.osda.viewer.drawer.viewport.fitBounds(currentBounds);
|
||||
}
|
||||
// animate to the annotation
|
||||
$('html,body').animate({
|
||||
scrollTop: $(annotator.osda.viewer.element).offset().top
|
||||
}, 'slow');
|
||||
}
|
||||
}
|
||||
waitingOsda();
|
||||
}
|
||||
} else { // It is a text
|
||||
var hasRanges = typeof an.ranges !== 'undefined' && typeof an.ranges[0] !== 'undefined';
|
||||
var startOffset = hasRanges ? an.ranges[0].startOffset : '';
|
||||
var endOffset = hasRanges ? an.ranges[0].endOffset : '';
|
||||
|
||||
if (typeof startOffset !== 'undefined' && typeof endOffset !== 'undefined') {
|
||||
// change the color
|
||||
$(an.highlights).addClass('api');
|
||||
// animate to the annotation
|
||||
$('html,body').animate({
|
||||
scrollTop: $(an.highlights[0]).offset().top
|
||||
}, 'slow');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (parseInt(API.method, 10) === 2) {
|
||||
if (typeof mplayer !== 'undefined') {
|
||||
// variable for Video
|
||||
var container = decodeURIComponent(API.container);
|
||||
var player = mplayer[container];
|
||||
var isVideo = (typeof player !== 'undefined' && container === player.id_);
|
||||
var isNumber = (!isNaN(parseFloat(API.start)) && isFinite(API.start) && !isNaN(parseFloat(API.end)) && isFinite(API.end));
|
||||
var isSource = false;
|
||||
|
||||
if (isVideo) {
|
||||
// Compare without extension
|
||||
var src = decodeURIComponent(API.src);
|
||||
var targetSrc = src.substring(0, src.lastIndexOf("."));
|
||||
var playerSrc = (player.tech.options_.source.src === '') ? player.tag.currentSrc : player.tech.options_.source.src;
|
||||
playerSrc = playerSrc.substring(0, playerSrc.lastIndexOf("."));
|
||||
isSource = (targetSrc === playerSrc);
|
||||
}
|
||||
|
||||
// Open Video Annotation
|
||||
if (isVideo && isNumber && isSource) {
|
||||
var annotation = {
|
||||
rangeTime: {
|
||||
start: API.start,
|
||||
end: API.end
|
||||
},
|
||||
created: new Date().toISOString(),
|
||||
updated: new Date().toISOString(),
|
||||
target: {
|
||||
container: container,
|
||||
src: src
|
||||
},
|
||||
media: 'video',
|
||||
text: decodeURIComponent(API.text),
|
||||
user: decodeURIComponent(API.user)
|
||||
};
|
||||
videojs(player.id_).ready(function(){
|
||||
if (player.techName !== 'Youtube'){
|
||||
player.preload('auto');
|
||||
}
|
||||
player.autoPlayAPI = annotation;
|
||||
player.play();
|
||||
});
|
||||
}
|
||||
}
|
||||
// variable for text
|
||||
var startOffset = API.startOffset;
|
||||
var endOffset = API.endOffset;
|
||||
|
||||
// Text Annotation
|
||||
if (!isVideo && typeof startOffset !== 'undefined' && typeof endOffset !== 'undefined') {
|
||||
var annotation = {
|
||||
ranges: [{
|
||||
start: decodeURIComponent(API.start),
|
||||
end: decodeURIComponent(API.end),
|
||||
startOffset: decodeURIComponent(API.startOffset),
|
||||
endOffset: decodeURIComponent(API.endOffset),
|
||||
}],
|
||||
created: new Date().toISOString(),
|
||||
updated: new Date().toISOString(),
|
||||
media: 'text',
|
||||
text: decodeURIComponent(API.text),
|
||||
user: decodeURIComponent(API.user)
|
||||
};
|
||||
// show the annotation
|
||||
annotator.setupAnnotation(annotation);
|
||||
// to change the color
|
||||
$(annotation.highlights).addClass('api');
|
||||
// animate to the annotation
|
||||
$('html, body').animate({
|
||||
scrollTop: $(annotation.highlights[0]).offset().top
|
||||
}, 'slow');
|
||||
}
|
||||
// variables for images
|
||||
var Left = API.Left;
|
||||
var Top = API.Top;
|
||||
var Width = API.Width;
|
||||
var Height = API.Height;
|
||||
var leftZoom = API.leftZoom;
|
||||
var topZoom = API.topZoom;
|
||||
var widthZoom = API.widthZoom;
|
||||
var heightZoom = API.heightZoom;
|
||||
|
||||
// Image Annotation
|
||||
if (!isVideo && typeof Left !== 'undefined' && typeof Top !== 'undefined' && typeof Width !== 'undefined' && typeof Height !== 'undefined' && typeof leftZoom !== 'undefined' && typeof topZoom !== 'undefined' && typeof widthZoom !== 'undefined' && typeof heightZoom !== 'undefined') {
|
||||
var an = {
|
||||
rangePosition: {
|
||||
width: parseFloat(decodeURIComponent(API.Width)),
|
||||
top: parseFloat(decodeURIComponent(API.Top)),
|
||||
left: parseFloat(decodeURIComponent(API.Left)),
|
||||
height: parseFloat(decodeURIComponent(API.Height)),
|
||||
},
|
||||
bounds: {
|
||||
width: parseFloat(decodeURIComponent(API.widthZoom)),
|
||||
x: parseFloat(decodeURIComponent(API.leftZoom)),
|
||||
y: parseFloat(decodeURIComponent(API.topZoom)),
|
||||
height: parseFloat(decodeURIComponent(API.heightZoom)),
|
||||
},
|
||||
target:{
|
||||
container: API.container,
|
||||
src: API.src
|
||||
},
|
||||
created: new Date().toISOString(),
|
||||
updated: new Date().toISOString(),
|
||||
media: 'image',
|
||||
text: decodeURIComponent(API.text),
|
||||
user: decodeURIComponent(API.user)
|
||||
};
|
||||
|
||||
var isOpenViewer = typeof annotator.osda !== "undefined" && typeof annotator.osda.viewer !== "undefined";
|
||||
function waitingOsda() {
|
||||
isOpenViewer = typeof annotator.osda !== "undefined" && typeof annotator.osda.viewer !== "undefined";
|
||||
if (!isOpenViewer) {
|
||||
setTimeout(waitingOsda, 200);
|
||||
} else {
|
||||
// show the annotation
|
||||
annotator.plugins['Store'].annotations.push(an);
|
||||
annotator.osda.viewer.annotationInstance.drawRect(an);
|
||||
// change the color
|
||||
$(an.highlights).addClass('api');
|
||||
// change zoom
|
||||
var currentBounds = annotator.osda.viewer.drawer.viewport.getBounds();
|
||||
var bounds = typeof an.bounds !== 'undefined' ? an.bounds : {};
|
||||
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;
|
||||
}
|
||||
annotator.osda.viewer.drawer.viewport.fitBounds(currentBounds);
|
||||
// animate to the annotation
|
||||
$('html,body').animate({
|
||||
scrollTop: $(annotator.osda.viewer.element).offset().top
|
||||
}, 'slow');
|
||||
}
|
||||
}
|
||||
waitingOsda();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// Let know to others API that this plugin is loaded
|
||||
annotator.isShareLoaded = true;
|
||||
annotator.publish('shareloaded');
|
||||
}
|
||||
Share.prototype.runAPI = function(API) {
|
||||
var self = this;
|
||||
var func = function(annotations) {
|
||||
self.runningAPI(annotations, API);
|
||||
self.annotator.unsubscribe("annotationsLoaded", func);
|
||||
};
|
||||
this.annotator
|
||||
// -- Finished the Annotator DOM
|
||||
.subscribe("annotationsLoaded", func);
|
||||
}
|
||||
|
||||
Share.prototype._isVideo = function(an) {
|
||||
// Detect if the annotation is a Open Video Annotation
|
||||
var an = an || {};
|
||||
var rt = an.rangeTime;
|
||||
var isVideo = (typeof an.media !== 'undefined' && an.media === 'video');
|
||||
var hasContainer = (typeof an.target !== 'undefined' && typeof an.target.container !== 'undefined' );
|
||||
var isNumber = (typeof rt !== 'undefined' && !isNaN(parseFloat(rt.start)) && isFinite(rt.start) && !isNaN(parseFloat(rt.end)) && isFinite(rt.end));
|
||||
return (isVideo && hasContainer && isNumber);
|
||||
}
|
||||
|
||||
Share.prototype._isImage = function(annotation) {
|
||||
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' && typeof an.target.container !== 'undefined');
|
||||
var isImage = (typeof an.media !== 'undefined' && an.media === 'image');
|
||||
var isRP = (typeof rp !== 'undefined');
|
||||
return (isOpenSeaDragon && isContainer && isImage && isRP);
|
||||
}
|
||||
|
||||
Share.prototype.getParameterByName = function(name) {
|
||||
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
||||
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
|
||||
var results = regex.exec('?' + window.location.href.split('?')[1]);
|
||||
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
};
|
||||
|
||||
Share.prototype.removeVariableFromURL = function(url_string, variable_name) {
|
||||
var URL = String(url_string);
|
||||
var regex = new RegExp( "\\?" + variable_name + "=[^&]*&?", "gi");
|
||||
URL = URL.replace(regex,'?');
|
||||
regex = new RegExp( "\\&" + variable_name + "=[^&]*&?", "gi");
|
||||
URL = URL.replace(regex,'&');
|
||||
URL = URL.replace(/(\?|&)$/,'');
|
||||
regex = null;
|
||||
return URL;
|
||||
}
|
||||
|
||||
Share.prototype.updateViewer = function(field, annotation) {
|
||||
this.annotation = annotation;
|
||||
|
||||
var self = this;
|
||||
var field = $(field);
|
||||
var ret = field.addClass('share-viewer-annotator').html(function() {
|
||||
var string;
|
||||
return self.buildHTMLShareButton('Share:', self.getSource('ovaId'));
|
||||
});
|
||||
|
||||
// Create the actions for the buttons
|
||||
this.buttonsActions(field[0], 1, this.options.baseUrl); // 1 is the method of the API that will be for share some annotation in the database
|
||||
return ret;
|
||||
};
|
||||
|
||||
return Share;
|
||||
|
||||
})(Annotator.Plugin);
|
||||
@@ -1 +0,0 @@
|
||||
.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px!important;height:9px!important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:green;color:#fff}.mce-spellchecker-word{background:url(img/wline.gif) repeat-x bottom left;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#39f!important}.mce-edit-focus{outline:1px dotted #333}
|
||||
@@ -1 +0,0 @@
|
||||
body{background-color:#fff;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;scrollbar-3dlight-color:#f0f0ee;scrollbar-arrow-color:#676662;scrollbar-base-color:#f0f0ee;scrollbar-darkshadow-color:#ddd;scrollbar-face-color:#e0e0dd;scrollbar-highlight-color:#f0f0ee;scrollbar-shadow-color:#f0f0ee;scrollbar-track-color:#f5f5f5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px!important;height:9px!important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:green;color:#fff}.mce-spellchecker-word{background:url(img/wline.gif) repeat-x bottom left;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#39f!important}.mce-edit-focus{outline:1px dotted #333}
|
||||
@@ -1,175 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>
|
||||
This is a custom SVG font generated by IcoMoon.
|
||||
<iconset grid="16"></iconset>
|
||||
</metadata>
|
||||
<defs>
|
||||
<font id="icomoon-small" horiz-adv-x="512" >
|
||||
<font-face units-per-em="512" ascent="480" descent="-32" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph class="hidden" unicode="" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
|
||||
<glyph unicode="" d="M 352,64l0,18.502 c 75.674,30.814, 128,96.91, 128,173.498c0,106.039-100.288,192-224,192S 32,362.039, 32,256
|
||||
c0-76.588, 52.327-142.684, 128-173.498L 160,64 L 64,64 l-32,48l0-112 l 160,0 L 192,111.406 c-50.45,25.681-85.333,80.77-85.333,144.594
|
||||
c0,88.366, 66.859,160, 149.333,160c 82.474,0, 149.333-71.634, 149.333-160c0-63.824-34.883-118.913-85.333-144.594L 320,0 l 160,0 L 480,112 l-32-48
|
||||
L 352,64 z" />
|
||||
<glyph unicode="" d="M 128,448l0-448 l 128,128l 128-128L 384,448 L 128,448 z M 352,85.255l-96,96l-96-96L 160,416 l 192,0 L 352,85.255 z" />
|
||||
<glyph unicode="" d="M 463.637,364.892l-66.745,66.744C 386.34,442.188, 372.276,448, 357.293,448s-29.047-5.812-39.598-16.363l-82.746-82.745
|
||||
c-21.834-21.834-21.834-57.362,0-79.196l 1.373-1.373l 33.941,33.941l-1.373,1.373c-3.066,3.066-3.066,8.247,0,11.313l 82.746,82.746
|
||||
C 353.641,399.7, 356.040,400, 357.292,400s 3.651-0.299, 5.656-2.305l 66.745-66.744c 3.066-3.067, 3.066-8.249, 0.001-11.314l-82.747-82.747
|
||||
c-2.004-2.004-4.403-2.304-5.655-2.304s-3.651,0.3-5.656,2.306l-1.373,1.373l-33.94-33.942l 1.371-1.371
|
||||
c 10.553-10.554, 24.615-16.364, 39.6-16.364s 29.047,5.812, 39.598,16.363l 82.747,82.746C 485.47,307.53, 485.47,343.057, 463.637,364.892
|
||||
zM 275.678,179.678l-33.941-33.941l 1.373-1.373c 2.004-2.004, 2.305-4.403, 2.305-5.655c0-1.253-0.299-3.651-2.303-5.657
|
||||
l-82.747-82.745c-2.005-2.005-4.405-2.305-5.657-2.305s-3.652,0.3-5.657,2.305L 82.305,117.050C 80.3,119.055, 80,121.455, 80,122.707
|
||||
s 0.299,3.65, 2.305,5.656l 82.745,82.744c 2.005,2.006, 4.405,2.306, 5.657,2.306s 3.652-0.3, 5.657-2.306l 1.373-1.371l 33.941,33.94
|
||||
l-1.373,1.373c-10.552,10.552-24.615,16.363-39.598,16.363s-29.046-5.812-39.598-16.363l-82.744-82.743
|
||||
C 37.812,151.754, 32,137.689, 32,122.707s 5.812-29.047, 16.363-39.599l 66.745-66.745C 125.661,5.812, 139.724,0, 154.707,0
|
||||
s 29.046,5.812, 39.598,16.363l 82.747,82.746c 10.552,10.552, 16.361,24.615, 16.361,39.598s-5.812,29.047-16.363,39.598
|
||||
L 275.678,179.678zM 400,61c-4.862,0-9.725,1.854-13.435,5.565l-64,63.999c-7.422,7.42-7.422,19.449,0,26.869
|
||||
c 7.42,7.422, 19.448,7.422, 26.868,0l 64-64c 7.422-7.42, 7.422-19.448,0-26.868C 409.725,62.854, 404.862,61, 400,61zM 304,0c-8.837,0-16,7.163-16,16l0,64 c0,8.837, 7.163,16, 16,16s 16-7.163, 16-16l0-64 C 320,7.163, 312.837,0, 304,0zM 464,160l-64,0 c-8.837,0-16,7.163-16,16s 7.163,16, 16,16l 64,0 c 8.837,0, 16-7.163, 16-16S 472.837,160, 464,160zM 112,387c 4.862,0, 9.725-1.854, 13.435-5.565l 64-64c 7.421-7.42, 7.421-19.449,0-26.869c-7.42-7.422-19.449-7.422-26.869,0
|
||||
l-64,64c-7.421,7.42-7.421,19.449,0,26.869C 102.275,385.146, 107.138,387, 112,387zM 208,448c 8.837,0, 16-7.163, 16-16l0-64 c0-8.837-7.163-16-16-16s-16,7.163-16,16L 192,432 C 192,440.837, 199.163,448, 208,448zM 48,288l 64,0 c 8.837,0, 16-7.163, 16-16s-7.163-16-16-16L 48,256 c-8.837,0-16,7.163-16,16S 39.163,288, 48,288z" />
|
||||
<glyph unicode="" d="M 463.637,364.892l-66.745,66.744C 386.34,442.188, 372.276,448, 357.293,448s-29.047-5.812-39.598-16.363l-82.746-82.745
|
||||
c-21.834-21.834-21.834-57.362,0-79.196l 1.373-1.373l 33.941,33.941l-1.373,1.373c-3.066,3.066-3.066,8.247,0,11.313l 82.746,82.746
|
||||
C 353.641,399.7, 356.040,400, 357.292,400s 3.651-0.299, 5.656-2.305l 66.745-66.744c 3.066-3.067, 3.066-8.249, 0.001-11.314l-82.747-82.747
|
||||
c-2.004-2.004-4.403-2.304-5.655-2.304s-3.651,0.3-5.656,2.306l-1.373,1.373l-33.94-33.942l 1.371-1.371
|
||||
c 10.553-10.554, 24.615-16.364, 39.6-16.364s 29.047,5.812, 39.598,16.363l 82.747,82.746C 485.47,307.53, 485.47,343.057, 463.637,364.892
|
||||
zM 275.678,179.678l-33.941-33.941l 1.373-1.373c 2.004-2.004, 2.305-4.403, 2.305-5.655c0-1.253-0.299-3.651-2.303-5.657
|
||||
l-82.747-82.745c-2.005-2.005-4.405-2.305-5.657-2.305s-3.652,0.3-5.657,2.305L 82.305,117.050C 80.3,119.055, 80,121.455, 80,122.707
|
||||
s 0.299,3.65, 2.305,5.656l 82.745,82.744c 2.005,2.006, 4.405,2.306, 5.657,2.306s 3.652-0.3, 5.657-2.306l 1.373-1.371l 33.941,33.94
|
||||
l-1.373,1.373c-10.552,10.552-24.615,16.363-39.598,16.363s-29.046-5.812-39.598-16.363l-82.744-82.743
|
||||
C 37.812,151.754, 32,137.689, 32,122.707s 5.812-29.047, 16.363-39.599l 66.745-66.745C 125.661,5.812, 139.724,0, 154.707,0
|
||||
s 29.046,5.812, 39.598,16.363l 82.747,82.746c 10.552,10.552, 16.361,24.615, 16.361,39.598s-5.812,29.047-16.363,39.598
|
||||
L 275.678,179.678zM 176,125c-4.862,0-9.725,1.855-13.435,5.564c-7.42,7.42-7.42,19.449,0,26.869l 160,160c 7.42,7.42, 19.448,7.42, 26.868,0
|
||||
c 7.422-7.42, 7.422-19.45,0-26.87l-160-160C 185.725,126.855, 180.862,125, 176,125z" />
|
||||
<glyph unicode="" d="M 288,339.337L 288,448 l 168.001-168L 288,112L 288,223.048 C 92.547,227.633, 130.5,99.5, 160,0C 16,160, 53.954,345.437, 288,339.337z" />
|
||||
<glyph unicode="" d="M 352,0c 29.5,99.5, 67.453,227.633-128,223.048L 224,112 L 55.999,280L 224,448l0-108.663 C 458.046,345.437, 496,160, 352,0z" />
|
||||
<glyph unicode="" d="M 128.214,267.637c 52.9,0, 95.786-45.585, 95.786-101.819C 224,109.586, 181.114,64, 128.214,64
|
||||
c-52.901,0-95.786,45.585-95.786,101.818L 32,180.364C 32,292.829, 117.77,384, 223.572,384l0-58.182 c-36.55,0-70.913-15.13-96.758-42.602
|
||||
c-4.977-5.289-9.517-10.917-13.612-16.828C 118.094,267.208, 123.105,267.637, 128.214,267.637zM 384.214,267.637c 52.9,0, 95.786-45.585, 95.786-101.819C 480,109.586, 437.114,64, 384.214,64
|
||||
c-52.901,0-95.786,45.585-95.786,101.818L 288,180.364C 288,292.829, 373.77,384, 479.572,384l0-58.182 c-36.55,0-70.913-15.13-96.758-42.602
|
||||
c-4.978-5.289-9.518-10.917-13.612-16.828C 374.094,267.208, 379.105,267.637, 384.214,267.637z" />
|
||||
<glyph unicode="" d="M 32,384L 480,384L 480,320L 32,320zM 192,192L 480,192L 480,128L 192,128zM 192,288L 480,288L 480,224L 192,224zM 32,96L 480,96L 480,32L 32,32zM 32,288L 144,208L 32,128 z" />
|
||||
<glyph unicode="" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 320,192L 320,128L 32,128zM 32,288L 320,288L 320,224L 32,224zM 32,96L 480,96L 480,32L 32,32zM 480,288L 368,208L 480,128 z" />
|
||||
<glyph unicode="" d="M 192,416L 480,416L 480,352L 192,352zM 192,256L 480,256L 480,192L 192,192zM 192,96L 480,96L 480,32L 192,32zM 160,215L 160,288L 128,288L 128,448L 64,448L 64,416L 96,416L 96,288L 64,288L 64,256L 128,256L 128,231L 64,201L 64,128L 128,128L 128,96L 64,96L 64,64L 128,64L 128,32L 64,32L 64,0L 160,0L 160,160L 96,160L 96,185 z" />
|
||||
<glyph unicode="" d="M 192,416L 480,416L 480,352L 192,352zM 192,256L 480,256L 480,192L 192,192zM 192,96L 480,96L 480,32L 192,32zM 64,384A32,32 1980 1 1 128,384A32,32 1980 1 1 64,384zM 64,224A32,32 1980 1 1 128,224A32,32 1980 1 1 64,224zM 64,64A32,32 1980 1 1 128,64A32,32 1980 1 1 64,64z" />
|
||||
<glyph unicode="" d="M 444,288l-28,0 L 416,416 l 32,0 L 448,448 L 288,448 l0-32 l 32,0 l0-128 L 192,288 L 192,416 l 32,0 L 224,448 L 64,448 l0-32 l 32,0 l0-128 L 68,288 c-19.8,0-36-16.2-36-36l0-216 c0-19.8, 16.2-36, 36-36l 120,0
|
||||
c 19.8,0, 36,16.2, 36,36L 224,192 l 64,0 l0-156 c0-19.8, 16.2-36, 36-36l 120,0 c 19.8,0, 36,16.2, 36,36L 480,252 C 480,271.8, 463.8,288, 444,288z M 174,32L 82,32
|
||||
c-9.9,0-18,7.2-18,16s 8.1,16, 18,16l 92,0 c 9.9,0, 18-7.2, 18-16S 183.9,32, 174,32z M 272,224l-32,0 c-8.8,0-16,7.2-16,16s 7.2,16, 16,16l 32,0
|
||||
c 8.8,0, 16-7.2, 16-16S 280.8,224, 272,224z M 430,32l-92,0 c-9.9,0-18,7.2-18,16s 8.1,16, 18,16l 92,0 c 9.9,0, 18-7.2, 18-16S 439.9,32, 430,32z" />
|
||||
<glyph unicode="" d="M 352,288l0,80 c0,8.8-7.2,16-16,16l-80,0 L 256,416 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,384 c-8.801,0-16-7.2-16-16l0-256
|
||||
c0-8.8, 7.199-16, 16-16l 112,0 l0-96 l 192,0 l 96,96L 448,288 L 352,288 z M 160,415.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
|
||||
c 0.021-0.018, 0.041-0.038, 0.059-0.057L 224,384 l-64,0 L 160,415.943 L 160,415.943z M 96,320l0,32 l 192,0 l0-32 L 96,320 z M 352,45.255L 352,96 l 50.745,0 L 352,45.255z
|
||||
M 416,128l-96,0 l0-96 L 192,32 L 192,256 l 224,0 L 416,128 z" />
|
||||
<glyph unicode="" d="M 416,320l-96,0 l0,32 l-96,96L 32,448 l0-352 l 192,0 l0-96 l 288,0 L 512,224 L 416,320z M 416,274.745L 466.745,224L 416,224 L 416,274.745 z M 224,402.745L 274.745,352
|
||||
L 224,352 L 224,402.745 z M 64,416l 128,0 l0-96 l 96,0 l0-192 L 64,128 L 64,416 z M 480,32L 256,32 l0,64 l 64,0 L 320,288 l 64,0 l0-96 l 96,0 L 480,32 z" />
|
||||
<glyph unicode="" d="M 432.204,144.934c-23.235,23.235-53.469,34.002-80.541,31.403L 320,208l 96,96c0,0, 64,64,0,128L 256,272L 96,432
|
||||
c-64-64,0-128,0-128l 96-96l-31.663-31.663c-27.072,2.599-57.305-8.169-80.54-31.403c-37.49-37.49-42.556-93.209-11.313-124.45
|
||||
c 31.241-31.241, 86.96-26.177, 124.45,11.313c 23.235,23.234, 34.001,53.469, 31.403,80.54L 256,144l 31.664-31.664
|
||||
c-2.598-27.072, 8.168-57.305, 31.403-80.539c 37.489-37.49, 93.209-42.556, 124.449-11.313
|
||||
C 474.76,51.725, 469.694,107.443, 432.204,144.934z M 176.562,100.711c-1.106-12.166-7.51-24.913-17.57-34.973
|
||||
C 147.886,54.631, 133.452,48, 120.383,48c-5.262,0-12.649,1.114-17.958,6.424c-10.703,10.702-8.688,36.566, 11.313,56.568
|
||||
c 11.106,11.107, 25.54,17.738, 38.609,17.738c 5.262,0, 12.649-1.114, 17.958-6.424C 176.861,115.751, 177.040,105.962, 176.562,100.711z
|
||||
M 256,176c-17.673,0-32,14.327-32,32s 14.327,32, 32,32s 32-14.327, 32-32S 273.673,176, 256,176z M 409.576,54.424
|
||||
c-5.31-5.31-12.696-6.424-17.958-6.424c-13.069,0-27.503,6.631-38.609,17.738c-10.061,10.060-16.464,22.807-17.569,34.973
|
||||
c-0.479,5.251-0.3,15.040, 6.257,21.596c 5.309,5.311, 12.695,6.424, 17.958,6.424c 13.068,0, 27.503-6.631, 38.608-17.737
|
||||
C 418.265,90.99, 420.279,65.126, 409.576,54.424z" />
|
||||
<glyph unicode="" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 32,288L 480,288L 480,224L 32,224zM 32,96L 480,96L 480,32L 32,32z" />
|
||||
<glyph unicode="" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 128,288L 384,288L 384,224L 128,224zM 128,96L 384,96L 384,32L 128,32z" />
|
||||
<glyph unicode="" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 192,288L 480,288L 480,224L 192,224zM 192,96L 480,96L 480,32L 192,32z" />
|
||||
<glyph unicode="" d="M 32,384L 480,384L 480,320L 32,320zM 32,192L 480,192L 480,128L 32,128zM 32,288L 320,288L 320,224L 32,224zM 32,96L 320,96L 320,32L 32,32z" />
|
||||
<glyph unicode="" d="M 480,224l-4.571,0 L 347.062,224 c-25.039,17.71-57.215,27.43-91.062,27.43c-44.603,0-82.286,25.121-82.286,54.856
|
||||
c0,29.735, 37.683,54.857, 82.286,54.857c 37.529,0, 70.154-17.788, 79.56-41.143l 56.508,0 c-3.965,25.322-18.79,48.984-42.029,66.413
|
||||
C 324.599,405.493, 291.201,416, 256,416c-35.202,0-68.598-10.507-94.037-29.587c-27.394-20.545-43.106-49.751-43.106-80.127
|
||||
s 15.712-59.582, 43.106-80.127c 0.978-0.733, 1.971-1.449, 2.973-2.158L 36.571,224.001 L 32,224.001 l0-32 l 256.266,0 c 29.104-8.553, 50.021-28.135, 50.021-50.286
|
||||
c0-29.734-37.684-54.855-82.286-54.855c-37.53,0-70.154,17.787-79.559,41.143l-56.508,0 c 3.965-25.32, 18.791-48.984, 42.030-66.413
|
||||
C 187.402,42.508, 220.798,32, 256,32c 35.201,0, 68.599,10.508, 94.037,29.587c 27.395,20.545, 43.104,49.751, 43.104,80.127
|
||||
c0,17.649-5.327,34.896-15.147,50.286L 480,192 L 480,224 z" />
|
||||
<glyph unicode="" d="M 96,64l 288,0 l0-32 L 96,32 L 96,64 zM 320,416l0-192 c0-15.656-7.35-30.812-20.695-42.676C 283.834,167.573, 262.771,160, 240,160c-22.772,0-43.834,7.573-59.304,21.324
|
||||
C 167.35,193.188, 160,208.344, 160,224L 160,416 L 96,416 l0-192 c0-70.691, 64.471-128, 144-128c 79.529,0, 144,57.309, 144,128L 384,416 L 320,416 z" />
|
||||
<glyph unicode="" d="M 416,416l0-32 l-72,0 L 216,64l 72,0 l0-32 L 64,32 l0,32 l 72,0 L 264,384l-72,0 L 192,416 L 416,416 z" />
|
||||
<glyph unicode="" d="M 312.721,232.909C 336.758,251.984, 352,280.337, 352,312c0,57.438-50.145,104-112,104L 128,416 l0-384 l 144,0
|
||||
c 61.856,0, 112,46.562, 112,104C 384,180.098, 354.441,217.781, 312.721,232.909z M 192,328c0,13.255, 10.745,24, 24,24l 33.602,0
|
||||
C 270.809,352, 288,330.51, 288,304s-17.191-48-38.398-48L 192,256 L 192,328 z M 273.6,96L 216,96 c-13.255,0-24,10.745-24,24l0,72 l 81.6,0
|
||||
c 21.209,0, 38.4-21.49, 38.4-48S 294.809,96, 273.6,96z" />
|
||||
<glyph unicode="" d="M 425.373,358.627l-66.746,66.745C 346.183,437.818, 321.6,448, 304,448L 96,448 c-17.6,0-32-14.4-32-32l0-384 c0-17.6, 14.4-32, 32-32l 320,0
|
||||
c 17.6,0, 32,14.4, 32,32L 448,304 C 448,321.6, 437.817,346.182, 425.373,358.627z M 402.745,336.001c 3.396-3.398, 6.896-9.581, 9.447-16.001L 320,320
|
||||
L 320,412.193 c 6.42-2.55, 12.602-6.050, 16-9.448L 402.745,336.001z M 415.942,32L 96.057,32 c-0.020,0.017-0.041,0.038-0.057,0.058L 96,415.943
|
||||
c 0.017,0.020, 0.038,0.041, 0.057,0.057L 288,416 l0-128 l 128,0 l0-255.942 C 415.983,32.038, 415.962,32.017, 415.942,32z" />
|
||||
<glyph unicode="" d="M 480,40L 480,335.969 L 368.031,448L 72,448 c-22.091,0-40-17.908-40-40l0-368 c0-22.092, 17.909-40, 40-40l 368,0
|
||||
C 462.092,0, 480,17.908, 480,40z M 288,384l 32,0 l0-96 l-32,0 L 288,384 z M 352,64L 160,64 L 160,191.941 c 0.017,0.021, 0.038,0.041, 0.058,0.059l 191.885,0
|
||||
c 0.020-0.018, 0.041-0.038, 0.058-0.059L 352,64L 352,64z M 416,64l-32,0 L 384,192 c0,17.6-14.4,32-32,32L 160,224 c-17.6,0-32-14.4-32-32l0-128 L 96,64 L 96,384
|
||||
l 32,0 l0-96 c0-17.6, 14.4-32, 32-32l 160,0 c 17.6,0, 32,14.4, 32,32l0,85.505 l 64-64.036L 416,64 z" />
|
||||
<glyph unicode="" d="M 32,384l0-352 l 448,0 L 480,384 L 32,384 z M 192,160l0,64 l 128,0 l0-64 L 192,160 z M 320,128l0-64 L 192,64 l0,64 L 320,128 z M 320,320l0-64 L 192,256 l0,64 L 320,320 z M 160,320l0-64 L 64,256 l0,64 L 160,320
|
||||
z M 64,224l 96,0 l0-64 L 64,160 L 64,224 z M 352,224l 96,0 l0-64 l-96,0 L 352,224 z M 352,256l0,64 l 96,0 l0-64 L 352,256 z M 64,128l 96,0 l0-64 L 64,64 L 64,128 z M 352,64l0,64 l 96,0 l0-64 L 352,64 z" />
|
||||
<glyph unicode="" d="M 256,410c 49.683,0, 96.391-19.347, 131.521-54.478S 442,273.683, 442,224s-19.348-96.391-54.479-131.521S 305.683,38, 256,38
|
||||
s-96.391,19.348-131.522,54.479S 70,174.317, 70,224s 19.347,96.391, 54.478,131.522S 206.317,410, 256,410 M 256,448
|
||||
C 132.288,448, 32,347.712, 32,224s 100.288-224, 224-224s 224,100.288, 224,224S 379.712,448, 256,448L 256,448zM 160,288A32,32 1980 1 1 224,288A32,32 1980 1 1 160,288zM 288,288A32,32 1980 1 1 352,288A32,32 1980 1 1 288,288zM 256,152c-50.92,0-96.28,18.437-125.583,47.164C 141.98,140.36, 193.806,96, 256,96c 62.194,0, 114.020,44.36, 125.584,103.164
|
||||
C 352.28,170.437, 306.92,152, 256,152z" />
|
||||
<glyph unicode="" d="M 240,288L 144,384L 208,448L 32,448L 32,272L 96,336L 192,240 zM 320,240L 416,336L 480,272L 480,448L 304,448L 368,384L 272,288 zM 272,160L 368,64L 304,0L 480,0L 480,176L 416,112L 320,208 zM 192,208L 96,112L 32,176L 32,0L 208,0L 144,64L 240,160 z" />
|
||||
<glyph unicode="" d="M 32,256L 480,256L 480,192L 32,192z" />
|
||||
<glyph unicode="" d="M 32,96l 256,0 l0-64 L 32,32 L 32,96 z M 384,384L 273.721,384 l-91.883-256l-66.144,0 l 91.881,256L 96,384 L 96,448 l 288,0 L 384,384 z M 464.887,32L 400,96.887
|
||||
L 335.113,32L 304,63.113L 368.887,128L 304,192.887L 335.113,224L 400,159.113L 464.887,224L 496,192.887L 431.113,128L 496,63.113
|
||||
L 464.887,32z" />
|
||||
<glyph unicode="" d="M 128,416l 256,0 l0-64 L 128,352 L 128,416 z M 448,320L 64,320 c-17.6,0-32-14.4-32-32l0-128 c0-17.6, 14.398-32, 32-32l 64,0 l0-96 l 256,0 l0,96 l 64,0
|
||||
c 17.6,0, 32,14.4, 32,32L 480,288 C 480,305.6, 465.6,320, 448,320z M 352,64L 160,64 L 160,192 l 192,0 L 352,64 z M 455.2,272c0-12.813-10.387-23.2-23.199-23.2
|
||||
S 408.8,259.187, 408.8,272s 10.389,23.2, 23.201,23.2C 444.814,295.2, 455.2,284.813, 455.2,272z" />
|
||||
<glyph unicode="" d="M 192,416c-61.856,0-112-50.144-112-112s 50.144-112, 112-112l0-160 l 64,0 L 256,352 l 32,0 l0-320 l 64,0 L 352,352 l 64,0 L 416,416 L 192,416 z" />
|
||||
<glyph unicode="" d="M 224,416c-61.856,0-112-50.144-112-112s 50.144-112, 112-112l0-160 l 64,0 L 288,352 l 32,0 l0-320 l 64,0 L 384,352 l 64,0 L 448,416 L 224,416 zM 32,32L 144,128L 32,224 z" />
|
||||
<glyph unicode="" d="M 160,416C 98.144,416, 48,365.856, 48,304s 50.144-112, 112-112l0-160 l 64,0 L 224,352 l 32,0 l0-320 l 64,0 L 320,352 l 64,0 L 384,416 L 160,416 zM 480,224L 368,128L 480,32 z" />
|
||||
<glyph unicode="" d="M 256,288L 320,288L 320,256L 256,256zM 256,96L 320,96L 320,64L 256,64zM 288,192L 352,192L 352,160L 288,160zM 384,192L 384,96L 352,96L 352,64L 416,64L 416,192 zM 192,192L 256,192L 256,160L 192,160zM 160,96L 224,96L 224,64L 160,64zM 160,288L 224,288L 224,256L 160,256zM 96,384L 96,256L 128,256L 128,352L 160,352L 160,384 zM 352,256L 416,256L 416,384L 384,384L 384,288L 352,288 zM 32,448l0-448 l 448,0 L 480,448 L 32,448 z M 448,32L 64,32 L 64,416 l 384,0 L 448,32 zM 96,192L 96,64L 128,64L 128,160L 160,160L 160,192 zM 288,384L 352,384L 352,352L 288,352zM 192,384L 256,384L 256,352L 192,352z" />
|
||||
<glyph unicode="" d="M 408,448l 8-192L 96,256 l 8,192l 16,0 l 8-160l 256,0 l 8,160L 408,448 z M 104,0l-8,160l 320,0 l-8-160l-16,0 l-8,128L 128,128 l-8-128L 104,0 zM 32,224L 96,224L 96,192L 32,192zM 128,224L 192,224L 192,192L 128,192zM 224,224L 288,224L 288,192L 224,192zM 320,224L 384,224L 384,192L 320,192zM 416,224L 480,224L 480,192L 416,192z" />
|
||||
<glyph unicode="" d="M 480,416L 480,448 l-96,0 c-17.601,0-32-14.4-32-32l0-160 c0-7.928, 2.929-15.201, 7.748-20.807L 208,105l-71,74l-41-35l 112-144l 208,224l 64,0
|
||||
l0,32 l-96,0 L 384,416 L 480,416 zM 128,224l 32,0 L 160,416 c0,17.6-14.4,32-32,32L 64,448 c-17.6,0-32-14.4-32-32l0-192 l 32,0 l0,96 l 64,0 L 128,224 z M 64,352L 64,416 l 64,0 l0-64 L 64,352 zM 320,256l0,48 c0,17.6-4.4,32-22,32c 17.6,0, 22,14.4, 22,32L 320,416 c0,17.6-14.4,32-32,32l-96,0 l0-224 l 96,0 C 305.6,224, 320,238.4, 320,256z
|
||||
M 224,416l 64,0 l0-64 l-64,0 L 224,416 z M 224,320l 64,0 l0-64 l-64,0 L 224,320 z" />
|
||||
<glyph unicode="" d="M 224,224l-64,0 l0,64 l 64,0 l0,64 l 64,0 l0-64 l 64,0 l0-64 l-64,0 l0-64 l-64,0 L 224,224 z M 480,192l0-160 L 32,32 L 32,192 l 64,0 l0-96 l 320,0 l0,96 L 480,192 z" />
|
||||
<glyph unicode="" d="M 208,128L 112,224L 208,320L 176,352L 48,224L 176,96 zM 336,352L 304,320L 400,224L 304,128L 336,96L 464,224 z" />
|
||||
<glyph unicode="" d="M 224,128l 64,0 l0-64 l-64,0 L 224,128 z M 352,352c 17.673,0, 32-14.327, 32-32l0-83 l-114-77l-46,0 l0,32 l 96,64l0,32 L 160,288 l0,64 L 352,352 z M 256,448
|
||||
c-59.833,0-116.083-23.3-158.392-65.608C 55.301,340.083, 32,283.833, 32,224c0-59.832, 23.301-116.084, 65.608-158.392
|
||||
C 139.917,23.3, 196.167,0, 256,0c 59.832,0, 116.084,23.3, 158.392,65.608C 456.7,107.916, 480,164.168, 480,224
|
||||
c0,59.833-23.3,116.083-65.608,158.392C 372.084,424.7, 315.832,448, 256,448z" />
|
||||
<glyph unicode="" d="M 448,416L 64,416 c-17.6,0-32-14.4-32-32l0-320 c0-17.6, 14.4-32, 32-32l 384,0 c 17.6,0, 32,14.4, 32,32L 480,384 C 480,401.6, 465.6,416, 448,416z
|
||||
M 448,64.058c-0.006-0.007-0.015-0.014-0.021-0.021L 352,224l-80-64L 160,304L 64.016,64.042c-0.005,0.005-0.011,0.011-0.016,0.016
|
||||
L 64,383.943 c 0.017,0.020, 0.038,0.041, 0.057,0.057l 383.885,0 c 0.020-0.017, 0.041-0.038, 0.058-0.058L 448,64.058 zM 320,304A48,48 1980 1 1 416,304A48,48 1980 1 1 320,304z" />
|
||||
<glyph unicode="" d="M 448,416L 64,416 c-17.6,0-32-14.4-32-32l0-320 c0-17.6, 14.4-32, 32-32l 384,0 c 17.6,0, 32,14.4, 32,32L 480,384 C 480,401.6, 465.6,416, 448,416z
|
||||
M 128,64L 64,64 l0,64 l 64,0 L 128,64 z M 128,192L 64,192 l0,64 l 64,0 L 128,192 z M 128,320L 64,320 L 64,384 l 64,0 L 128,320 z M 352,64L 160,64 L 160,384 l 192,0 L 352,64 z M 448,64l-64,0 l0,64 l 64,0 L 448,64 z
|
||||
M 448,192l-64,0 l0,64 l 64,0 L 448,192 z M 448,320l-64,0 L 384,384 l 64,0 L 448,320 zM 192,320L 192,128L 336,224 z" />
|
||||
<glyph unicode="" d="M 38.899,327.688l 40.707-25.441C 105.007,342.804, 144,373.974, 190.21,389.37l-15.183,45.547
|
||||
C 118.153,415.968, 70.163,377.604, 38.899,327.688zM 336.973,434.917L 321.79,389.37c 46.211-15.396, 85.202-46.566, 110.604-87.124l 40.706,25.441
|
||||
C 441.837,377.604, 393.847,415.968, 336.973,434.917zM 303.987,127.996c-2.404,0-4.846,0.545-7.143,1.693L 224,166.111L 224,272 c0,8.836, 7.164,16, 16,16s 16-7.164, 16-16l0-86.111
|
||||
l 55.155-27.578c 7.903-3.951, 11.107-13.562, 7.155-21.466C 315.508,131.238, 309.856,127.997, 303.987,127.996zM 256,384C 149.961,384, 64,298.039, 64,192c0-106.039, 85.961-192, 192-192c 106.039,0, 192,85.961, 192,192
|
||||
C 448,298.039, 362.039,384, 256,384z M 256,48c-79.529,0-144,64.471-144,144c0,79.529, 64.471,144, 144,144c 79.529,0, 144-64.471, 144-144
|
||||
C 400,112.471, 335.529,48, 256,48z" />
|
||||
<glyph unicode="" d="M 32,252.127c 22.659,24.96, 48.581,46.18, 76.636,62.562C 153.802,341.061, 204.759,355, 256,355
|
||||
c 51.24,0, 102.198-13.939, 147.363-40.312c 28.056-16.382, 53.978-37.602, 76.637-62.562l0,58.716
|
||||
c-16.505,14.059-34.062,26.57-52.434,37.297C 375.063,378.796, 315.737,395, 256,395s-119.064-16.204-171.567-46.86
|
||||
C 66.062,337.413, 48.505,324.901, 32,310.842L 32,252.127 zM 256,320c-91.598,0-172.919-50.278-224-128c 51.081-77.724, 132.402-128, 224-128c 91.598,0, 172.919,50.276, 224,128
|
||||
C 428.919,269.722, 347.598,320, 256,320z M 256,224c0-17.673-14.327-32-32-32s-32,14.327-32,32c0,17.674, 14.327,32, 32,32
|
||||
S 256,241.674, 256,224z M 364.033,131.669C 330.316,111.982, 293.969,102, 256,102s-74.316,9.982-108.033,29.669
|
||||
C 122.19,146.721, 98.659,167.324, 78.91,192c 19.749,24.675, 43.28,45.279, 69.058,60.33c 6.638,3.876, 13.379,7.37, 20.213,10.491
|
||||
C 162.925,250.95, 160,237.817, 160,224c0-53.020, 42.981-96, 96-96c 53.020,0, 96,42.98, 96,96c0,13.817-2.925,26.95-8.18,38.821
|
||||
c 6.834-3.122, 13.575-6.615, 20.213-10.491c 25.777-15.051, 49.308-35.655, 69.058-60.33
|
||||
C 413.342,167.324, 389.811,146.721, 364.033,131.669z" />
|
||||
<glyph unicode="" d="M 325.584,338.083C 313.278,379.064, 311.146,384, 272,384l-32,0 c-39.809,0-41.332-5.076-54.209-48c0-0.001,0-0.001-0.001-0.002
|
||||
L 113.791,96l 56.818,0 l 28.8,96l 113.183,0 l 28.8-96l 56.815,0 L 325.584,338.083z M 218.609,256l 19.2,68c 5.043,16.809, 18.19,15, 18.19,15
|
||||
s 13.147,1.809, 18.19-15l 0.002,0 l 19.2-68L 218.609,256 z" />
|
||||
<glyph unicode="" d="M 288,448 C 411.712,448 512,347.712 512,224 C 512,100.288 411.712,0 288,0 L 288,48 C 335.012,48 379.209,66.307 412.451,99.549 C 445.693,132.791 464,176.988 464,224 C 464,271.011 445.693,315.209 412.451,348.451 C 379.209,381.693 335.012,400 288,400 C 240.989,400 196.791,381.693 163.549,348.451 C 137.979,322.882 121.258,290.828 114.896,256 L 208,256 L 96,128 L -16,256 L 66.285,256 C 81.815,364.551 175.154,448 288,448 ZM 384,256 L 384,192 L 256,192 L 256,352 L 320,352 L 320,256 Z" />
|
||||
<glyph unicode="" d="M 512,183.771l0,80.458 l-79.572,7.957c-4.093,15.021-10.044,29.274-17.605,42.49l 52.298,63.919L 410.595,435.12l-63.918-52.298
|
||||
c-13.217,7.562-27.471,13.513-42.491,17.604L 296.229,480l-80.458,0 l-7.957-79.573c-15.021-4.093-29.274-10.043-42.49-17.604
|
||||
L 101.405,435.12L 44.88,378.595l 52.298-63.918c-7.562-13.216-13.513-27.47-17.605-42.49L0,264.229l0-80.458 l 79.573-7.957
|
||||
c 4.093-15.021, 10.043-29.274, 17.605-42.491L 44.88,69.405l 56.524-56.524l 63.919,52.298c 13.216-7.562, 27.47-13.514, 42.49-17.605
|
||||
L 215.771-32l 80.458,0 l 7.957,79.572c 15.021,4.093, 29.274,10.044, 42.491,17.605l 63.918-52.298l 56.524,56.524l-52.298,63.918
|
||||
c 7.562,13.217, 13.514,27.471, 17.605,42.49L 512,183.771z M 352,192l-64-64l-64,0 l-64,64l0,64 l 64,64l 64,0 l 64-64L 352,192 z" />
|
||||
<glyph unicode="" d="M 384,377 L 384,352 L 448,352 L 448,320 L 352,320 L 352,393 L 416,423 L 416,448 L 352,448 L 352,480 L 448,480 L 448,407 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
|
||||
<glyph unicode="" d="M 384,25 L 384,0 L 448,0 L 448-32 L 352-32 L 352,41 L 416,71 L 416,96 L 352,96 L 352,128 L 448,128 L 448,55 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
|
||||
<glyph unicode="" d="M 352,288l0,80 c0,8.8-7.2,16-16,16l-80,0 L 256,416 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,384 c-8.801,0-16-7.2-16-16
|
||||
l0-256 c0-8.8, 7.199-16, 16-16l 112,0 l0-96 l 288,0 L 448,288 L 352,288 z M 160,415.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
|
||||
c 0.021-0.018, 0.041-0.038, 0.059-0.057L 224,384 l-64,0 L 160,415.943 z M 96,320l0,32 l 192,0 l0-32 L 96,320 z M 416,32L 192,32 L 192,256 l 224,0 L 416,32 zM 224,224L 224,160L 240,160L 256,192L 288,192L 288,96L 264,96L 264,64L 344,64L 344,96L 320,96L 320,192L 352,192L 368,160L 384,160L 384,224 z" />
|
||||
<glyph unicode="" d="M 384,352L 416,352L 416,320L 384,320zM 320,288L 352,288L 352,256L 320,256zM 320,224L 352,224L 352,192L 320,192zM 320,160L 352,160L 352,128L 320,128zM 256,224L 288,224L 288,192L 256,192zM 256,160L 288,160L 288,128L 256,128zM 192,160L 224,160L 224,128L 192,128zM 384,288L 416,288L 416,256L 384,256zM 384,224L 416,224L 416,192L 384,192zM 384,160L 416,160L 416,128L 384,128zM 384,96L 416,96L 416,64L 384,64zM 320,96L 352,96L 352,64L 320,64zM 256,96L 288,96L 288,64L 256,64zM 192,96L 224,96L 224,64L 192,64zM 128,96L 160,96L 160,64L 128,64z" />
|
||||
<glyph unicode="" d="M 464,416L 256,416L 240,448L 64,448L 32,384L 480,384 zM 420.17,128L 464,128 l 16,224L 32,352 l 32-320l 178.040,0 C 189.599,50.888, 152,101.133, 152,160c0,74.991, 61.009,136, 136,136
|
||||
c 74.99,0, 136-61.009, 136-136C 424,149.161, 422.689,138.425, 420.17,128zM 437.498,55.125l-67.248,55.346C 378.977,124.932, 384,141.878, 384,160c0,53.020-42.98,96-96,96s-96-42.98-96-96
|
||||
s 42.98-96, 96-96c 18.122,0, 35.069,5.023, 49.529,13.75l 55.346-67.248c 11.481-13.339, 31.059-14.070, 43.503-1.626l 2.746,2.746
|
||||
C 451.568,24.066, 450.837,43.644, 437.498,55.125z M 288,98c-34.242,0-62,27.758-62,62s 27.758,62, 62,62s 62-27.758, 62-62
|
||||
S 322.242,98, 288,98z" />
|
||||
<glyph unicode=" " horiz-adv-x="256" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 25 KiB |
@@ -1,153 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>
|
||||
This is a custom SVG font generated by IcoMoon.
|
||||
<iconset grid="16"></iconset>
|
||||
</metadata>
|
||||
<defs>
|
||||
<font id="icomoon" horiz-adv-x="512" >
|
||||
<font-face units-per-em="512" ascent="480" descent="-32" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph class="hidden" unicode="" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
|
||||
<glyph unicode="" d="M 464,416L 256,416L 240,448L 64,448L 32,384L 480,384 zM 452.17,128l 37.43,0 L 512,352L0,352 l 32-320l 242.040,0 C 221.599,50.888, 184,101.133, 184,160c0,74.991, 61.009,136, 136,136
|
||||
c 74.99,0, 136-61.009, 136-136C 456,149.161, 454.689,138.425, 452.17,128zM 501.498,23.125l-99.248,87.346C 410.977,124.931, 416,141.878, 416,160c0,53.020-42.98,96-96,96s-96-42.98-96-96
|
||||
s 42.98-96, 96-96c 18.122,0, 35.069,5.023, 49.529,13.75l 87.346-99.248c 11.481-13.339, 31.059-14.070, 43.503-1.626l 2.746,2.746
|
||||
C 515.568-7.934, 514.837,11.644, 501.498,23.125z M 320,98c-34.242,0-62,27.758-62,62s 27.758,62, 62,62s 62-27.758, 62-62
|
||||
S 354.242,98, 320,98z" />
|
||||
<glyph unicode="" d="M 384,352L 416,352L 416,320L 384,320zM 320,288L 352,288L 352,256L 320,256zM 320,224L 352,224L 352,192L 320,192zM 320,160L 352,160L 352,128L 320,128zM 256,224L 288,224L 288,192L 256,192zM 256,160L 288,160L 288,128L 256,128zM 192,160L 224,160L 224,128L 192,128zM 384,288L 416,288L 416,256L 384,256zM 384,224L 416,224L 416,192L 384,192zM 384,160L 416,160L 416,128L 384,128zM 384,96L 416,96L 416,64L 384,64zM 320,96L 352,96L 352,64L 320,64zM 256,96L 288,96L 288,64L 256,64zM 192,96L 224,96L 224,64L 192,64zM 128,96L 160,96L 160,64L 128,64z" />
|
||||
<glyph unicode="" d="M 416,352l-96,0 L 320,384 L 224,480L0,480 l0-384 l 192,0 l0-128 l 320,0 L 512,256 L 416,352z M 416,306.745L 466.745,256L 416,256 L 416,306.745 z M 224,434.745L 274.745,384L 224,384
|
||||
L 224,434.745 z M 32,448l 160,0 l0-96 l 96,0 l0-224 L 32,128 L 32,448 z M 480,0L 224,0 l0,96 l 96,0 L 320,320 l 64,0 l0-96 l 96,0 L 480,0 z" />
|
||||
<glyph unicode="" d="M 128,448 L 384,448 L 384,384 L 320,384 L 320,0 L 256,0 L 256,384 L 192,384 L 192,0 L 128,0 L 128,224 C 66.144,224 16,274.144 16,336 C 16,397.856 66.144,448 128,448 ZM 480,32L 352,144L 480,256 z" />
|
||||
<glyph unicode="" d="M 224,448 L 480,448 L 480,384 L 416,384 L 416,0 L 352,0 L 352,384 L 288,384 L 288,0 L 224,0 L 224,224 C 162.144,224 112,274.144 112,336 C 112,397.856 162.144,448 224,448 ZM 32,256L 160,144L 32,32 z" />
|
||||
<glyph unicode="" d="M 192,448 L 448,448 L 448,384 L 384,384 L 384,0 L 320,0 L 320,384 L 256,384 L 256,0 L 192,0 L 192,224 C 130.144,224 80,274.144 80,336 C 80,397.856 130.144,448 192,448 Z" />
|
||||
<glyph unicode="" d="M 365.71,221.482 C 397.67,197.513 416,163.439 416,128 C 416,92.561 397.67,58.487 365.71,34.518 C 336.031,12.259 297.068,0 256,0 C 214.931,0 175.969,12.259 146.29,34.518 C 114.33,58.487 96,92.561 96,128 L 160,128 C 160,93.309 203.963,64 256,64 C 308.037,64 352,93.309 352,128 C 352,162.691 308.037,192 256,192 C 214.931,192 175.969,204.259 146.29,226.518 C 114.33,250.488 96,284.561 96,320 C 96,355.439 114.33,389.512 146.29,413.482 C 175.969,435.741 214.931,448 256,448 C 297.068,448 336.031,435.741 365.71,413.482 C 397.67,389.512 416,355.439 416,320 L 352,320 C 352,354.691 308.037,384 256,384 C 203.963,384 160,354.691 160,320 C 160,285.309 203.963,256 256,256 C 297.068,256 336.031,243.741 365.71,221.482 ZM0,224L 512,224L 512,192L0,192z" />
|
||||
<glyph unicode="" d="M 352,448 L 416,448 L 416,240 C 416,160.471 344.366,96 256,96 C 167.635,96 96,160.471 96,240 L 96,448 L 160,448 L 160,240 C 160,219.917 169.119,200.648 185.677,185.747 C 204.125,169.145 229.1,160 256,160 C 282.9,160 307.875,169.145 326.323,185.747 C 342.881,200.648 352,219.917 352,240 L 352,448 ZM 96,64L 416,64L 416,0L 96,0z" />
|
||||
<glyph unicode="" d="M 448,448 L 448,416 L 384,416 L 224,32 L 288,32 L 288,0 L 64,0 L 64,32 L 128,32 L 288,416 L 224,416 L 224,448 Z" />
|
||||
<glyph unicode="" d="M 353.94,237.674C 372.689,259.945, 384,288.678, 384,320c0,70.58-57.421,128-128,128l-64,0 l-64,0 L 96,448 l0-448 l 32,0 l 64,0 l 96,0
|
||||
c 70.579,0, 128,57.421, 128,128C 416,174.478, 391.101,215.248, 353.94,237.674z M 192,384l 50.75,0 c 27.984,0, 50.75-28.71, 50.75-64
|
||||
s-22.766-64-50.75-64L 192,256 L 192,384 z M 271.5,64L 192,64 L 192,192 l 79.5,0 c 29.225,0, 53-28.71, 53-64S 300.725,64, 271.5,64z" />
|
||||
<glyph unicode="" d="M 192,64L 288,64L 288-32L 192-32zM 400,448 C 426.51,448 448,426.51 448,400 L 448,256 L 288,160 L 288,96 L 192,96 L 192,192 L 352,288 L 352,352 L 96,352 L 96,448 L 400,448 Z" />
|
||||
<glyph unicode="" d="M 288,448 C 411.712,448 512,347.712 512,224 C 512,100.288 411.712,0 288,0 L 288,48 C 335.012,48 379.209,66.307 412.451,99.549 C 445.693,132.791 464,176.988 464,224 C 464,271.011 445.693,315.209 412.451,348.451 C 379.209,381.693 335.012,400 288,400 C 240.989,400 196.791,381.693 163.549,348.451 C 137.979,322.882 121.258,290.828 114.896,256 L 208,256 L 96,128 L -16,256 L 66.285,256 C 81.815,364.551 175.154,448 288,448 ZM 384,256 L 384,192 L 256,192 L 256,352 L 320,352 L 320,256 Z" />
|
||||
<glyph unicode="" d="M0,224L 64,224L 64,192L0,192zM 96,224L 192,224L 192,192L 96,192zM 224,224L 288,224L 288,192L 224,192zM 320,224L 416,224L 416,192L 320,192zM 448,224L 512,224L 512,192L 448,192zM 440,480 L 448,256 L 64,256 L 72,480 L 88,480 L 96,288 L 416,288 L 424,480 ZM 72-32 L 64,160 L 448,160 L 440-32 L 424-32 L 416,128 L 96,128 L 88-32 Z" />
|
||||
<glyph unicode="" d="M 192,384L 256,384L 256,352L 192,352zM 288,384L 352,384L 352,352L 288,352zM 448,384 L 448,256 L 352,256 L 352,288 L 416,288 L 416,352 L 384,352 L 384,384 ZM 160,288L 224,288L 224,256L 160,256zM 256,288L 320,288L 320,256L 256,256zM 96,352 L 96,288 L 128,288 L 128,256 L 64,256 L 64,384 L 160,384 L 160,352 ZM 192,192L 256,192L 256,160L 192,160zM 288,192L 352,192L 352,160L 288,160zM 448,192 L 448,64 L 352,64 L 352,96 L 416,96 L 416,160 L 384,160 L 384,192 ZM 160,96L 224,96L 224,64L 160,64zM 256,96L 320,96L 320,64L 256,64zM 96,160 L 96,96 L 128,96 L 128,64 L 64,64 L 64,192 L 160,192 L 160,160 ZM 480,448 L 32,448 L 32,0 L 480,0 L 480,448 Z M 512,480 L 512,480 L 512-32 L 0-32 L 0,480 L 512,480 Z" />
|
||||
<glyph unicode="" d="M 224,192 L 128,192 L 128,256 L 224,256 L 224,352 L 288,352 L 288,256 L 384,256 L 384,192 L 288,192 L 288,96 L 224,96 ZM 512,160 L 512-32 L 0-32 L 0,160 L 64,160 L 64,32 L 448,32 L 448,160 Z" />
|
||||
<glyph unicode="" d="M 64,352l 64,0 l0-96 l 32,0 L 160,448 c0,17.6-14.4,32-32,32L 64,480 C 46.4,480, 32,465.6, 32,448l0-192 l 32,0 L 64,352 z M 64,448l 64,0 l0-64 L 64,384 L 64,448 z M 480,448L 480,480 l-96,0
|
||||
c-17.601,0-32-14.4-32-32l0-160 c0-17.6, 14.399-32, 32-32l 96,0 l0,32 l-96,0 L 384,448 L 480,448 z M 320,400L 320,448 c0,17.6-14.4,32-32,32l-96,0 l0-224 l 96,0
|
||||
c 17.6,0, 32,14.4, 32,32l0,48 c0,17.6-4.4,32-22,32C 315.6,368, 320,382.4, 320,400z M 288,288l-64,0 l0,64 l 64,0 L 288,288 z M 288,384l-64,0 L 224,448 l 64,0 L 288,384 zM 416,192 L 208-32 L 96,112 L 137,147 L 208,73 L 384,224 Z" />
|
||||
<glyph unicode="" d="M 512,480 L 512,288 L 442.87,357.13 L 336.87,251.13 L 283.13,304.87 L 389.13,410.87 L 320,480 ZM 122.87,410.87 L 228.87,304.87 L 175.13,251.13 L 69.13,357.13 L 0,288 L 0,480 L 192,480 ZM 442.87,90.87 L 512,160 L 512-32 L 320-32 L 389.13,37.13 L 283.13,143.13 L 336.87,196.87 ZM 228.87,143.13 L 122.87,37.13 L 192-32 L 0-32 L 0,160 L 69.13,90.87 L 175.13,196.87 Z" />
|
||||
<glyph unicode="" d="M 128,448L 384,448L 384,384L 128,384zM 480,352L 32,352 C 14.4,352,0,337.6,0,320l0-160 c0-17.6, 14.398-32, 32-32l 96,0 l0-128 l 256,0 L 384,128 l 96,0 c 17.6,0, 32,14.4, 32,32L 512,320
|
||||
C 512,337.6, 497.6,352, 480,352z M 352,32L 160,32 L 160,192 l 192,0 L 352,32 z M 487.2,304c0-12.813-10.387-23.2-23.199-23.2
|
||||
c-12.813,0-23.201,10.387-23.201,23.2s 10.388,23.2, 23.201,23.2C 476.814,327.2, 487.2,316.813, 487.2,304z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.386,0,224c0-141.385, 114.614-256, 256-256c 141.385,0, 256,114.615, 256,256
|
||||
C 512,365.386, 397.385,480, 256,480z M 256,8c-119.293,0-216,96.706-216,216c0,119.293, 96.707,216, 216,216c 119.295,0, 216-96.707, 216-216
|
||||
C 472,104.706, 375.295,8, 256,8z M 192,320c0-17.673-14.327-32-32-32s-32,14.327-32,32s 14.327,32, 32,32S 192,337.673, 192,320z
|
||||
M 384,320c0-17.673-14.326-32-32-32s-32,14.327-32,32s 14.326,32, 32,32S 384,337.673, 384,320zM 256,154 C 326.537,154 387.344,182.766 415.231,215.596 C 404.795,129.986 337.087,64 256,64 C 174.941,64 107.251,130.013 96.778,215.584 C 124.671,182.761 185.471,154 256,154 Z" />
|
||||
<glyph unicode="" d="M 352,32 L 480,32 L 512,96 L 512-32 L 320-32 L 320,75.107 C 385.556,103.349 432,173.688 432,256 C 432,363.216 353.201,447.133 256,447.133 C 158.797,447.133 80,363.217 80,256 C 80,173.688 126.443,103.349 192,75.107 L 192-32 L 0-32 L 0,96 L 32,32 L 160,32 L 160,48.295 C 66.185,81.525 0,161.996 0,256 C 0,379.712 114.615,480 256,480 C 397.385,480 512,379.712 512,256 C 512,161.996 445.815,81.525 352,48.295 L 352,32 Z" />
|
||||
<glyph unicode="" d="M 384,377 L 384,352 L 448,352 L 448,320 L 352,320 L 352,393 L 416,423 L 416,448 L 352,448 L 352,480 L 448,480 L 448,407 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
|
||||
<glyph unicode="" d="M 384,25 L 384,0 L 448,0 L 448-32 L 352-32 L 352,41 L 416,71 L 416,96 L 352,96 L 352,128 L 448,128 L 448,55 ZM 338,352L 270,352L 176,258L 82,352L 14,352L 142,224L 14,96L 82,96L 176,190L 270,96L 338,96L 210,224 z" />
|
||||
<glyph unicode="" d="M0,32L 288,32L 288-32L0-32zM 96,480L 448,480L 448,416L 96,416zM 138.694,64 L 241.038,456.082 L 302.963,439.918 L 204.838,64 ZM 464.887-32 L 400,32.887 L 335.113-32 L 304-0.887 L 368.887,64 L 304,128.887 L 335.113,160 L 400,95.113 L 464.887,160 L 496,128.887 L 431.113,64 L 496-0.887 Z" />
|
||||
<glyph unicode="" d="M0,256L 512,256L 512,192L0,192z" />
|
||||
<glyph unicode="" d="M0,448l0-448 l 512,0 L 512,448 L0,448 z M 192,160l0,96 l 128,0 l0-96 L 192,160 z M 320,128l0-96 L 192,32 l0,96 L 320,128 z M 320,384l0-96 L 192,288 L 192,384 L 320,384 z M 160,384l0-96 L 32,288 L 32,384 L 160,384 z
|
||||
M 32,256l 128,0 l0-96 L 32,160 L 32,256 z M 352,256l 128,0 l0-96 L 352,160 L 352,256 z M 352,288L 352,384 l 128,0 l0-96 L 352,288 z M 32,128l 128,0 l0-96 L 32,32 L 32,128 z M 352,32l0,96 l 128,0 l0-96 L 352,32 z" />
|
||||
<glyph unicode="" d="M 161.009,64l 28.8,96l 132.382,0 l 28.8-96l 56.816,0 L 311.809,384L 200.191,384 l-96-320L 161.009,64 z M 237.809,320l 36.382,0 l 28.8-96l-93.982,0
|
||||
L 237.809,320z" />
|
||||
<glyph unicode="" d="M 256,320C 151.316,320, 58.378,269.722,0,192c 58.378-77.723, 151.316-128, 256-128c 104.684,0, 197.622,50.277, 256,128
|
||||
C 453.622,269.722, 360.684,320, 256,320z M 224,256c 17.673,0, 32-14.327, 32-32s-14.327-32-32-32s-32,14.327-32,32S 206.327,256, 224,256z
|
||||
M 386.808,127.352c-19.824-10.129-40.826-17.931-62.423-23.188C 302.141,98.746, 279.134,96, 256,96
|
||||
c-23.133,0-46.141,2.746-68.384,8.162c-21.597,5.259-42.599,13.061-62.423,23.188c-31.51,16.101-60.111,38.205-83.82,64.649
|
||||
c 23.709,26.444, 52.31,48.55, 83.82,64.649c 16.168,8.261, 33.121,14.973, 50.541,20.020C 165.79,261.547, 160,243.451, 160,224
|
||||
c0-53.020, 42.981-96, 96-96c 53.019,0, 96,42.98, 96,96c0,19.451-5.791,37.547-15.733,52.67c 17.419-5.048, 34.372-11.76, 50.541-20.021
|
||||
c 31.511-16.099, 60.109-38.204, 83.819-64.649C 446.917,165.557, 418.318,143.45, 386.808,127.352z M 430.459,358.139
|
||||
C 376.099,385.916, 317.403,400, 256,400c-61.403,0-120.099-14.084-174.459-41.861C 52.155,343.123, 24.675,324.187,0,302.101l0-54.603
|
||||
c 27.669,29.283, 60.347,53.877, 96.097,72.145C 145.907,345.095, 199.706,358, 256,358s 110.093-12.905, 159.902-38.358
|
||||
c 35.751-18.268, 68.429-42.862, 96.098-72.145L 512,302.1 C 487.325,324.187, 459.846,343.123, 430.459,358.139z" />
|
||||
<glyph unicode="" d="M 256,384C 149.962,384, 64,298.039, 64,192s 85.961-192, 192-192c 106.037,0, 192,85.961, 192,192S 362.037,384, 256,384z
|
||||
M 357.822,90.177C 330.626,62.979, 294.464,48, 256,48s-74.625,14.979-101.823,42.177C 126.979,117.374, 112,153.536, 112,192
|
||||
s 14.979,74.625, 42.177,101.823C 181.375,321.021, 217.536,336, 256,336s 74.626-14.979, 101.821-42.177
|
||||
C 385.022,266.625, 400,230.464, 400,192S 385.021,117.374, 357.822,90.177zM 162.965,378.069l-21.47,42.939C 92.058,396.24, 51.76,355.942, 26.992,306.504l 42.938-21.47
|
||||
C 90.054,325.202, 122.796,357.945, 162.965,378.069zM 442.067,285.035l 42.939,21.469C 460.24,355.942, 419.943,396.24, 370.504,421.008l-21.472-42.939
|
||||
C 389.201,357.945, 421.944,325.203, 442.067,285.035zM 256,288l-32,0 l0-96 c0-5.055, 2.35-9.555, 6.011-12.486l-0.006-0.008l 80-64l 19.988,24.988L 256,199.689L 256,288 z" />
|
||||
<glyph unicode="" d="M 160,352L 32,224L 160,96L 224,96L 96,224L 224,352 zM 352,352L 288,352L 416,224L 288,96L 352,96L 480,224 z" />
|
||||
<glyph unicode="" d="M 224,128L 288,128L 288,64L 224,64zM 352,352 C 369.673,352 384,337.673 384,320 L 384,224 L 288,160 L 224,160 L 224,192 L 320,256 L 320,288 L 160,288 L 160,352 L 352,352 ZM 256,432 C 200.441,432 148.208,410.364 108.922,371.078 C 69.636,331.792 48,279.559 48,224 C 48,168.441 69.636,116.208 108.922,76.922 C 148.208,37.636 200.441,16 256,16 C 311.559,16 363.792,37.636 403.078,76.922 C 442.364,116.208 464,168.441 464,224 C 464,279.559 442.364,331.792 403.078,371.078 C 363.792,410.364 311.559,432 256,432 Z M 256,480 L 256,480 C 397.385,480 512,365.385 512,224 C 512,82.615 397.385-32 256-32 C 114.615-32 0,82.615 0,224 C 0,365.385 114.615,480 256,480 Z" />
|
||||
<glyph unicode="" d="M0,416l0-384 l 512,0 L 512,416 L0,416 z M 96,64L 32,64 l0,64 l 64,0 L 96,64 z M 96,192L 32,192 l0,64 l 64,0 L 96,192 z M 96,320L 32,320 L 32,384 l 64,0 L 96,320 z M 384,64L 128,64 L 128,384 l 256,0 L 384,64 z
|
||||
M 480,64l-64,0 l0,64 l 64,0 L 480,64 z M 480,192l-64,0 l0,64 l 64,0 L 480,192 z M 480,320l-64,0 L 416,384 l 64,0 L 480,320 zM 192,320L 192,128L 320,224 z" />
|
||||
<glyph unicode="" d="M0,416l0-416 l 512,0 L 512,416 L0,416 z M 480,32L 32,32 L 32,384 l 448,0 L 480,32 zM 352,304A48,48 1980 1 0 448,304A48,48 1980 1 0 352,304zM 448,64 L 64,64 L 160,320 L 288,160 L 352,208 Z" />
|
||||
<glyph unicode="" d="M 96,480l0-512 l 160,160l 160-160L 416,480 L 96,480 z M 384,45.255l-128,128l-128-128L 128,448 l 256,0 L 384,45.255 z" />
|
||||
<glyph unicode="" d="M 238.444,142.443c 2.28-4.524, 3.495-9.579, 3.495-14.848c0-8.808-3.372-17.029-9.496-23.154l-81.69-81.69
|
||||
c-6.124-6.124-14.348-9.496-23.154-9.496s-17.030,3.372-23.154,9.496l-49.69,49.69c-6.124,6.125-9.496,14.348-9.496,23.154
|
||||
s 3.372,17.030, 9.496,23.154l 81.69,81.691c 6.124,6.123, 14.348,9.496, 23.154,9.496c 5.269,0, 10.322-1.215, 14.848-3.494l 32.669,32.668
|
||||
c-13.935,10.705-30.72,16.080-47.517,16.080c-19.993,0-39.986-7.583-55.154-22.751l-81.69-81.691
|
||||
c-30.335-30.335-30.335-79.975,0-110.309l 49.69-49.691c 15.167-15.166, 35.16-22.75, 55.153-22.75
|
||||
c 19.994,0, 39.987,7.584, 55.154,22.751l 81.69,81.69c 27.91,27.91, 30.119,72.149, 6.672,102.673L 238.444,142.443zM 489.248,407.558l-49.69,49.691C 424.391,472.417, 404.398,480, 384.404,480c-19.993,0-39.985-7.583-55.153-22.751l-81.691-81.691
|
||||
c-27.91-27.91-30.119-72.149-6.671-102.671l 32.669,32.67c-2.279,4.525-3.494,9.58-3.494,14.847c0,8.808, 3.372,17.030, 9.496,23.154
|
||||
l 81.691,81.691c 6.123,6.124, 14.347,9.497, 23.153,9.497c 8.808,0, 17.030-3.373, 23.154-9.497l 49.69-49.691
|
||||
c 6.124-6.124, 9.496-14.347, 9.496-23.154c0-8.807-3.372-17.030-9.496-23.154l-81.69-81.691c-6.124-6.124-14.347-9.496-23.154-9.496
|
||||
c-5.268,0-10.322,1.215-14.848,3.495l-32.669-32.669c 13.936-10.705, 30.72-16.080, 47.517-16.080c 19.994,0, 39.987,7.584, 55.154,22.752
|
||||
l 81.69,81.69C 519.584,327.584, 519.584,377.223, 489.248,407.558zM 116.684,340.688L 20.687,436.685L 43.315,459.313L 139.312,363.316zM 192,480L 224,480L 224,384L 192,384zM0,288L 96,288L 96,256L0,256zM 395.316,107.312L 491.314,11.314L 468.686-11.314L 372.688,84.684zM 288,64L 320,64L 320-32L 288-32zM 416,192L 512,192L 512,160L 416,160z" />
|
||||
<glyph unicode="" d="M 160,128c 8.8-8.8, 23.637-8.363, 32.971,0.971L 351.030,287.029C 360.364,296.363, 360.8,311.2, 352,320
|
||||
s-23.637,8.363-32.971-0.971L 160.971,160.971C 151.637,151.637, 151.2,136.8, 160,128zM 238.444,142.444c 2.28-4.525, 3.495-9.58, 3.495-14.848c0-8.808-3.372-17.030-9.496-23.154l-81.691-81.691
|
||||
c-6.124-6.124-14.347-9.496-23.154-9.496s-17.030,3.372-23.154,9.496l-49.691,49.691c-6.124,6.124-9.496,14.347-9.496,23.154
|
||||
s 3.372,17.030, 9.496,23.154l 81.691,81.691c 6.124,6.124, 14.347,9.497, 23.154,9.497c 5.268,0, 10.322-1.215, 14.848-3.495l 32.669,32.669
|
||||
c-13.935,10.705-30.72,16.080-47.517,16.080c-19.993,0-39.986-7.583-55.154-22.751l-81.691-81.691
|
||||
c-30.335-30.335-30.335-79.974,0-110.309l 49.691-49.691C 87.611-24.416, 107.604-32, 127.597-32
|
||||
c 19.994,0, 39.987,7.584, 55.154,22.751l 81.691,81.691c 27.91,27.91, 30.119,72.149, 6.672,102.672L 238.444,142.444zM 489.249,407.558l-49.691,49.691C 424.391,472.417, 404.398,480, 384.404,480c-19.993,0-39.986-7.583-55.154-22.751l-81.691-81.691
|
||||
c-27.91-27.91-30.119-72.149-6.671-102.671l 32.669,32.67c-2.279,4.525-3.494,9.58-3.494,14.847c0,8.808, 3.372,17.030, 9.496,23.154
|
||||
l 81.691,81.691c 6.124,6.124, 14.347,9.497, 23.154,9.497s 17.030-3.373, 23.154-9.497l 49.691-49.691
|
||||
c 6.124-6.124, 9.496-14.347, 9.496-23.154s-3.372-17.030-9.496-23.154l-81.691-81.691c-6.124-6.124-14.347-9.496-23.154-9.496
|
||||
c-5.268,0-10.322,1.215-14.848,3.495l-32.669-32.669c 13.936-10.705, 30.72-16.080, 47.517-16.080c 19.994,0, 39.987,7.584, 55.154,22.751
|
||||
l 81.691,81.691C 519.584,327.584, 519.584,377.223, 489.249,407.558z" />
|
||||
<glyph unicode="" d="M 288,355.814L 288,480 l 192-192L 288,96L 288,222.912 C 64.625,228.153, 74.206,71.016, 131.070-32
|
||||
C-9.286,119.707, 20.52,362.785, 288,355.814z" />
|
||||
<glyph unicode="" d="M 380.931-32C 437.794,71.016, 447.375,228.153, 224,222.912L 224,96 L 32,288L 224,480l0-124.186
|
||||
C 491.481,362.785, 521.285,119.707, 380.931-32z" />
|
||||
<glyph unicode="" d="M 112.5,256 C 174.356,256 224.5,205.855 224.5,144 C 224.5,82.144 174.356,32 112.5,32 C 50.644,32 0.5,82.144 0.5,144 L 0,160 C 0,283.712 100.288,384 224,384 L 224,320 C 181.263,320 141.083,303.357 110.863,273.137 C 105.046,267.319 99.737,261.129 94.948,254.627 C 100.667,255.527 106.528,256 112.5,256 ZM 400.5,256 C 462.355,256 512.5,205.855 512.5,144 C 512.5,82.144 462.355,32 400.5,32 C 338.645,32 288.5,82.144 288.5,144 L 288,160 C 288,283.712 388.288,384 512,384 L 512,320 C 469.263,320 429.083,303.357 398.863,273.137 C 393.045,267.319 387.736,261.129 382.947,254.627 C 388.667,255.527 394.527,256 400.5,256 Z" />
|
||||
<glyph unicode="" d="M0,448L 512,448L 512,384L0,384zM 192,352L 512,352L 512,288L 192,288zM 192,256L 512,256L 512,192L 192,192zM 192,160L 512,160L 512,96L 192,96zM0,64L 512,64L 512,0L0,0zM 128,320 L 128,128 L 0,224 Z" />
|
||||
<glyph unicode="" d="M0,448L 512,448L 512,384L0,384zM 192,352L 512,352L 512,288L 192,288zM 192,256L 512,256L 512,192L 192,192zM 192,160L 512,160L 512,96L 192,96zM0,64L 512,64L 512,0L0,0zM 0,128 L 0,320 L 128,224 Z" />
|
||||
<glyph unicode="" d="M 192,64L 512,64L 512,0L 192,0zM 192,256L 512,256L 512,192L 192,192zM 192,448L 512,448L 512,384L 192,384zM 96,480 L 96,352 L 64,352 L 64,448 L 32,448 L 32,480 ZM 64,217 L 64,192 L 128,192 L 128,160 L 32,160 L 32,233 L 96,263 L 96,288 L 32,288 L 32,320 L 128,320 L 128,247 ZM 128,128 L 128-32 L 32-32 L 32,0 L 96,0 L 96,32 L 32,32 L 32,64 L 96,64 L 96,96 L 32,96 L 32,128 Z" />
|
||||
<glyph unicode="" d="M 192,448l 320,0 l0-64 L 192,384 L 192,448 z M 192,256l 320,0 l0-64 L 192,192 L 192,256 z M 192,64l 320,0 l0-64 L 192,0 L 192,64 zM0,416A64,64 1980 1 0 128,416A64,64 1980 1 0 0,416zM0,224A64,64 1980 1 0 128,224A64,64 1980 1 0 0,224zM0,32A64,64 1980 1 0 128,32A64,64 1980 1 0 0,32z" />
|
||||
<glyph unicode="" d="M 32,480L 224,480L 224,448L 32,448zM 288,480L 480,480L 480,448L 288,448zM 476,320l-28,0 L 448,448 L 320,448 l0-128 L 192,320 L 192,448 L 64,448 l0-128 L 36,320 c-19.8,0-36-16.2-36-36l0-280 c0-19.8, 16.2-36, 36-36l 152,0 c 19.8,0, 36,16.2, 36,36L 224,192 l 64,0
|
||||
l0-188 c0-19.8, 16.2-36, 36-36l 152,0 c 19.8,0, 36,16.2, 36,36L 512,284 C 512,303.8, 495.8,320, 476,320z M 174,0L 50,0 c-9.9,0-18,7.2-18,16
|
||||
s 8.1,16, 18,16l 124,0 c 9.9,0, 18-7.2, 18-16S 183.9,0, 174,0z M 272,224l-32,0 c-8.8,0-16,7.2-16,16s 7.2,16, 16,16l 32,0 c 8.8,0, 16-7.2, 16-16
|
||||
S 280.8,224, 272,224z M 462,0L 338,0 c-9.9,0-18,7.2-18,16s 8.1,16, 18,16l 124,0 c 9.9,0, 18-7.2, 18-16S 471.9,0, 462,0z" />
|
||||
<glyph unicode="" d="M 416,320L 416,400 c0,8.8-7.2,16-16,16L 288,416 L 288,448 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,416 c-8.801,0-16-7.2-16-16l0-320
|
||||
c0-8.8, 7.199-16, 16-16l 144,0 l0-96 l 224,0 l 96,96L 512,320 L 416,320 z M 192,447.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
|
||||
c 0.021-0.018, 0.041-0.038, 0.059-0.057L 256,416 l-64,0 L 192,447.943 z M 96,352L 96,384 l 256,0 l0-32 L 96,352 z M 416,13.255L 416,64 l 50.745,0 L 416,13.255z M 480,96l-96,0 l0-96
|
||||
L 224,0 L 224,288 l 256,0 L 480,96 z" />
|
||||
<glyph unicode="" d="M 445.387,125.423c-22.827,22.778-51.864,34.536-78.973,34.536l-14.556,0 l-31.952,32.004l 127.81,128.019
|
||||
c 31.952,32.005, 31.952,96.014,0,128.019L 256.001,255.973L 64.285,448c-31.952-32.004-31.952-96.014,0-128.019l 127.811-128.017
|
||||
l-31.953-32.004l-14.557,0 c-27.11,0-56.146-11.759-78.974-34.538c-40.811-40.721-46.325-101.242-12.315-135.175
|
||||
C 69.282-24.704, 89.441-32, 110.795-32c 27.108,0, 56.145,11.757, 78.973,34.536c 26.792,26.732, 38.371,62, 33.542,92.674l 32.692,32.744
|
||||
l 32.688-32.744c-4.828-30.674, 6.753-65.941, 33.542-92.674C 345.063-20.243, 374.098-32, 401.206-32
|
||||
c 21.354,0, 41.512,7.296, 56.497,22.248C 491.713,24.181, 486.197,84.702, 445.387,125.423z M 176.512,57.231
|
||||
c-3.849-8.941-9.505-17.173-16.813-24.463c-7.318-7.302-15.586-12.959-24.574-16.812c-8.066-3.458-16.48-5.284-24.331-5.284
|
||||
c-7.573,0-18.306,1.701-26.431,9.806c-8.068,8.052-9.76,18.659-9.76,26.144c0,7.771, 1.821,16.105, 5.263,24.106
|
||||
c 3.85,8.942, 9.507,17.173, 16.813,24.463c 7.317,7.303, 15.586,12.957, 24.575,16.812c 8.067,3.457, 16.48,5.284, 24.332,5.284
|
||||
c 7.573,0, 18.306-1.7, 26.429-9.807c 8.067-8.049, 9.761-18.658, 9.761-26.142C 181.777,73.567, 179.957,65.23, 176.512,57.231z
|
||||
M 256.002,146.702c-24.957,0-45.188,20.266-45.188,45.263c0,24.996, 20.231,45.26, 45.188,45.26s 45.186-20.264, 45.186-45.26
|
||||
C 301.188,166.966, 280.958,146.702, 256.002,146.702z M 427.636,20.479c-8.124-8.104-18.856-9.806-26.43-9.806
|
||||
c-7.852,0-16.265,1.826-24.333,5.284c-8.986,3.853-17.254,9.51-24.571,16.812c-7.307,7.29-12.963,15.521-16.813,24.463
|
||||
c-3.443,7.999-5.263,16.336-5.263,24.106c0,7.483, 1.692,18.094, 9.76,26.143c 8.123,8.104, 18.856,9.807, 26.43,9.807
|
||||
c 7.85,0, 16.265-1.827, 24.33-5.284c 8.989-3.854, 17.258-9.509, 24.575-16.812c 7.305-7.29, 12.962-15.521, 16.813-24.463
|
||||
c 3.442-7.999, 5.263-16.335, 5.263-24.106C 437.396,39.138, 435.702,28.53, 427.636,20.479z" />
|
||||
<glyph unicode="" d="M0,448L 512,448L 512,384L0,384zM0,352L 512,352L 512,288L0,288zM0,256L 512,256L 512,192L0,192zM0,160L 512,160L 512,96L0,96zM0,64L 512,64L 512,0L0,0z" />
|
||||
<glyph unicode="" d="M0,448L 512,448L 512,384L0,384zM 192,352L 512,352L 512,288L 192,288zM 192,160L 512,160L 512,96L 192,96zM0,256L 512,256L 512,192L0,192zM0,64L 512,64L 512,0L0,0z" />
|
||||
<glyph unicode="" d="M0,448L 512,448L 512,384L0,384zM 96,352L 416,352L 416,288L 96,288zM 96,160L 416,160L 416,96L 96,96zM0,256L 512,256L 512,192L0,192zM0,64L 512,64L 512,0L0,0z" />
|
||||
<glyph unicode="" d="M0,448L 512,448L 512,384L0,384zM0,352L 320,352L 320,288L0,288zM0,160L 320,160L 320,96L0,96zM0,256L 512,256L 512,192L0,192zM0,64L 512,64L 512,0L0,0z" />
|
||||
<glyph unicode="" d="M 512,183.771l0,80.458 l-79.572,7.957c-4.093,15.021-10.044,29.274-17.605,42.49l 52.298,63.919L 410.595,435.12l-63.918-52.298
|
||||
c-13.217,7.562-27.471,13.513-42.491,17.604L 296.229,480l-80.458,0 l-7.957-79.573c-15.021-4.093-29.274-10.043-42.49-17.604
|
||||
L 101.405,435.12L 44.88,378.595l 52.298-63.918c-7.562-13.216-13.513-27.47-17.605-42.49L0,264.229l0-80.458 l 79.573-7.957
|
||||
c 4.093-15.021, 10.043-29.274, 17.605-42.491L 44.88,69.405l 56.524-56.524l 63.919,52.298c 13.216-7.562, 27.47-13.514, 42.49-17.605
|
||||
L 215.771-32l 80.458,0 l 7.957,79.572c 15.021,4.093, 29.274,10.044, 42.491,17.605l 63.918-52.298l 56.524,56.524l-52.298,63.918
|
||||
c 7.562,13.217, 13.514,27.471, 17.605,42.49L 512,183.771z M 352,192l-64-64l-64,0 l-64,64l0,64 l 64,64l 64,0 l 64-64L 352,192 z" />
|
||||
<glyph unicode="" d="M 451.716,380.285l-71.432,71.431C 364.728,467.272, 334,480, 312,480L 72,480 C 50,480, 32,462, 32,440l0-432 c0-22, 18-40, 40-40l 368,0 c 22,0, 40,18, 40,40
|
||||
L 480,312 C 480,334, 467.272,364.729, 451.716,380.285z M 429.089,357.657c 1.565-1.565, 3.125-3.487, 4.64-5.657L 352,352 L 352,433.728
|
||||
c 2.17-1.515, 4.092-3.075, 5.657-4.64L 429.089,357.657z M 448,8c0-4.336-3.664-8-8-8L 72,0 c-4.336,0-8,3.664-8,8L 64,440 c0,4.336, 3.664,8, 8,8
|
||||
l 240,0 c 2.416,0, 5.127-0.305, 8-0.852L 320,320 l 127.148,0 c 0.547-2.873, 0.852-5.583, 0.852-8L 448,8 z" />
|
||||
<glyph unicode="" d="M 448,480L0,480 l0-512 l 512,0 L 512,416 L 448,480z M 256,416l 64,0 l0-128 l-64,0 L 256,416 z M 448,32L 64,32 L 64,416 l 32,0 l0-160 l 288,0 L 384,416 l 37.489,0 L 448,389.491L 448,32 z" />
|
||||
<glyph unicode="" d="M 64,208L 208,64L 448,304L 384,368L 208,192L 128,272 z" />
|
||||
<glyph unicode="" d="M 256,224L 256,160L 272,160L 288,192L 320,192L 320,64L 296,64L 296,32L 408,32L 408,64L 384,64L 384,192L 416,192L 432,160L 448,160L 448,224 zM 416,320L 416,400 c0,8.8-7.2,16-16,16L 288,416 L 288,448 c0,17.6-14.4,32-32,32l-64,0 c-17.602,0-32-14.4-32-32l0-32 L 48,416 c-8.801,0-16-7.2-16-16l0-320
|
||||
c0-8.8, 7.199-16, 16-16l 144,0 l0-96 l 320,0 L 512,320 L 416,320 z M 192,447.943c 0.017,0.019, 0.036,0.039, 0.057,0.057l 63.884,0
|
||||
c 0.021-0.018, 0.041-0.038, 0.059-0.057L 256,416 l-64,0 L 192,447.943 z M 96,352L 96,384 l 256,0 l0-32 L 96,352 z M 480,0L 224,0 L 224,288 l 256,0 L 480,0 z" />
|
||||
<glyph unicode=" " horiz-adv-x="256" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 53 B |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 152 B |
|
Before Width: | Height: | Size: 43 B |
|
Before Width: | Height: | Size: 46 B |