xblocks-core 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xblock_annotatable/.tx/config +8 -0
- xblock_annotatable/__init__.py +5 -0
- xblock_annotatable/block.py +307 -0
- xblock_annotatable/conf/locale/__init__.py +0 -0
- xblock_annotatable/conf/locale/config.yaml +93 -0
- xblock_annotatable/static/css/annotatable.css +188 -0
- xblock_annotatable/static/css/annotatable_editor.css +12 -0
- xblock_annotatable/static/js/src/annotatable.js +367 -0
- xblock_annotatable/static/js/src/annotatable_editor.js +74 -0
- xblock_annotatable/templates/annotatable.html +24 -0
- xblock_annotatable/templates/annotatable_editor.html +20 -0
- xblock_discussion/.tx/config +8 -0
- xblock_discussion/__init__.py +5 -0
- xblock_discussion/apps.py +53 -0
- xblock_discussion/block.py +265 -0
- xblock_discussion/conf/locale/__init__.py +0 -0
- xblock_discussion/conf/locale/config.yaml +93 -0
- xblock_discussion/public/css/inline-discussion-rtl.css +4572 -0
- xblock_discussion/public/css/inline-discussion.css +4572 -0
- xblock_discussion/public/js/discussion_bundle.js +2 -0
- xblock_discussion/templates/_discussion_inline_studio.html +16 -0
- xblock_discussion/templates/discussion_templates/_discussion_inline.html +49 -0
- xblock_discussion/templates/discussion_templates/_thread_list_template.html +55 -0
- xblock_discussion/templates/discussion_templates/_underscore_templates.html +19 -0
- xblock_discussion/templates/discussion_templates/templates.underscore +889 -0
- xblock_html/.tx/config +8 -0
- xblock_html/__init__.py +6 -0
- xblock_html/block.py +498 -0
- xblock_html/conf/locale/__init__.py +0 -0
- xblock_html/conf/locale/config.yaml +93 -0
- xblock_html/static/css/html.css +297 -0
- xblock_html/templates/html/announcement.yaml +18 -0
- xblock_html/templates/html/anon_user_id.yaml +19 -0
- xblock_html/templates/html/iframe.yaml +32 -0
- xblock_html/templates/html/raw.yaml +9 -0
- xblock_html/templates/html/zooming_image.yaml +239 -0
- xblock_lti/.tx/config +8 -0
- xblock_lti/__init__.py +7 -0
- xblock_lti/block.py +1018 -0
- xblock_lti/conf/locale/__init__.py +0 -0
- xblock_lti/conf/locale/config.yaml +93 -0
- xblock_lti/lti_2_util.py +388 -0
- xblock_lti/static/css/lti.css +57 -0
- xblock_lti/static/js/src/lti.js +23 -0
- xblock_lti/templates/lti.html +73 -0
- xblock_lti/templates/lti_form.html +38 -0
- xblock_pdf/__init__.py +3 -0
- xblock_pdf/block.py +129 -0
- xblock_pdf/js_tests/jquery.d.ts +5 -0
- xblock_pdf/js_tests/specs/helpers/loadAsElement.js +1 -0
- xblock_pdf/js_tests/specs/helpers/loadAsJQuery.js +1 -0
- xblock_pdf/js_tests/specs/helpers/mockRuntime.js +23 -0
- xblock_pdf/js_tests/specs/helpers/proveJQuery.js +12 -0
- xblock_pdf/js_tests/tsconfig.json +10 -0
- xblock_pdf/js_tests/vitest.config.ts +15 -0
- xblock_pdf/static/js/pdf.js +17 -0
- xblock_pdf/templates/html/pdf.html +22 -0
- xblock_pdf/utils.py +13 -0
- xblock_poll_question/.tx/config +8 -0
- xblock_poll_question/__init__.py +5 -0
- xblock_poll_question/block.py +311 -0
- xblock_poll_question/conf/locale/__init__.py +0 -0
- xblock_poll_question/conf/locale/config.yaml +93 -0
- xblock_poll_question/static/css/poll.css +356 -0
- xblock_poll_question/static/js/src/poll.js +196 -0
- xblock_poll_question/templates/poll.html +7 -0
- xblock_problem/.tx/config +8 -0
- xblock_problem/__init__.py +5 -0
- xblock_problem/block.py +2728 -0
- xblock_problem/capa/__init__.py +0 -0
- xblock_problem/capa/apps.py +54 -0
- xblock_problem/capa/capa_problem.py +1241 -0
- xblock_problem/capa/checker.py +174 -0
- xblock_problem/capa/correctmap.py +217 -0
- xblock_problem/capa/customrender.py +195 -0
- xblock_problem/capa/errors.py +62 -0
- xblock_problem/capa/inputtypes.py +1819 -0
- xblock_problem/capa/registry.py +57 -0
- xblock_problem/capa/responsetypes.py +3867 -0
- xblock_problem/capa/safe_exec/README.rst +43 -0
- xblock_problem/capa/safe_exec/__init__.py +4 -0
- xblock_problem/capa/safe_exec/exceptions.py +21 -0
- xblock_problem/capa/safe_exec/lazymod.py +43 -0
- xblock_problem/capa/safe_exec/remote_exec.py +142 -0
- xblock_problem/capa/safe_exec/safe_exec.py +506 -0
- xblock_problem/capa/static/applets/Protex.jar +0 -0
- xblock_problem/capa/static/applets/genex.jar +0 -0
- xblock_problem/capa/static/images/vsepr/AX2E0-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX2E1-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX2E2-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX2E3-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX3E0-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX3E1-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX3E2-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX4E0-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX4E1-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX4E2-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX5E1-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX5E2-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX6E0-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX6E1-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX7E0-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX8E0-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/AX9E0-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Bent-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Linear-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Linear-stick.png +0 -0
- xblock_problem/capa/static/images/vsepr/Octahedral-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Octahedral-stick.png +0 -0
- xblock_problem/capa/static/images/vsepr/Pentagonal-bipyramidal-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Pentagonal-planar-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Pentagonal-pyramidal-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Pyramidal-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Seesaw-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Square-antiprismatic-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Square-planar-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/T-shaped-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Tetrahedral-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Tetrahedral-stick.png +0 -0
- xblock_problem/capa/static/images/vsepr/Trigonal-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Trigonal-bipyramidal-3D-balls.png +0 -0
- xblock_problem/capa/static/images/vsepr/Trigonal-bipyramidal-stick.png +0 -0
- xblock_problem/capa/static/images/vsepr/Trigonal-planar-stick.png +0 -0
- xblock_problem/capa/static/js/capa/README +1 -0
- xblock_problem/capa/static/js/capa/annotationinput.js +98 -0
- xblock_problem/capa/static/js/capa/chemical_equation_preview.js +36 -0
- xblock_problem/capa/static/js/capa/choicetextinput.js +73 -0
- xblock_problem/capa/static/js/capa/design-protein-2d.js +85 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/base_image.js +45 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/config_parser.js +271 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/container.js +13 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/draggable_events.js +143 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/draggable_logic.js +400 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/draggables.js +281 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/main.js +107 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/scroller.js +162 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/state.js +95 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/targets.js +266 -0
- xblock_problem/capa/static/js/capa/drag_and_drop/update_input.js +373 -0
- xblock_problem/capa/static/js/capa/drag_and_drop.js +25 -0
- xblock_problem/capa/static/js/capa/edit-a-gene.js +71 -0
- xblock_problem/capa/static/js/capa/genex/21B31BA00E7CE7B6BD63DD13A8586A45.cache.html +652 -0
- xblock_problem/capa/static/js/capa/genex/63308EE54E8033A708B414CAC05B0C32.cache.html +642 -0
- xblock_problem/capa/static/js/capa/genex/7AC57DC6EC8C1D8672DDF6E6D4EF57CC.cache.html +628 -0
- xblock_problem/capa/static/js/capa/genex/9B4F4D4EFA24CDE2E4287CC07897F249.cache.html +654 -0
- xblock_problem/capa/static/js/capa/genex/A069AC107D79C29D6237614AC340F0C0.cache.html +652 -0
- xblock_problem/capa/static/js/capa/genex/C6220FCC8B9234FEAD8D826A73C6D2A4.cache.html +642 -0
- xblock_problem/capa/static/js/capa/genex/clear.cache.gif +0 -0
- xblock_problem/capa/static/js/capa/genex/genex.css +122 -0
- xblock_problem/capa/static/js/capa/genex/genex.nocache.js +18 -0
- xblock_problem/capa/static/js/capa/genex/hosted.html +365 -0
- xblock_problem/capa/static/js/capa/genex/images/circles.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/circles_ie6.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/corner.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/corner_ie6.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/hborder.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/hborder_ie6.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/thumb_horz.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/thumb_vertical.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/vborder.png +0 -0
- xblock_problem/capa/static/js/capa/genex/images/vborder_ie6.png +0 -0
- xblock_problem/capa/static/js/capa/jsinput/jsinput_example.css +9 -0
- xblock_problem/capa/static/js/capa/jsinput/jsinput_example.html +15 -0
- xblock_problem/capa/static/js/capa/jsinput/jsinput_example.js +86 -0
- xblock_problem/capa/static/js/capa/protex/39CC89519B0E1FCB47B935AC9FE13D7B.cache.html +743 -0
- xblock_problem/capa/static/js/capa/protex/6E05B1CD5BFCAF7D53C7C64D84318178.cache.html +750 -0
- xblock_problem/capa/static/js/capa/protex/C824A958AB642DC2213DFFDAC640BEAA.cache.html +760 -0
- xblock_problem/capa/static/js/capa/protex/D9267DE8FB02F8B995B4A58C66C76E29.cache.html +758 -0
- xblock_problem/capa/static/js/capa/protex/F275492F7098103BCB05F4F86ABF6218.cache.html +750 -0
- xblock_problem/capa/static/js/capa/protex/F3301B0E65F38C7FCF2EF3764B3BB0B6.cache.html +754 -0
- xblock_problem/capa/static/js/capa/protex/clear.cache.gif +0 -0
- xblock_problem/capa/static/js/capa/protex/hosted.html +365 -0
- xblock_problem/capa/static/js/capa/protex/protex.css +57 -0
- xblock_problem/capa/static/js/capa/protex/protex.nocache.js +18 -0
- xblock_problem/capa/static/js/capa/protex/scrollTableLoading.gif +0 -0
- xblock_problem/capa/static/js/capa/schematicinput.js +49 -0
- xblock_problem/capa/static/js/capa/src/formula_equation_preview.js +221 -0
- xblock_problem/capa/static/js/capa/src/jschannel.js +790 -0
- xblock_problem/capa/static/js/capa/src/jsinput.js +221 -0
- xblock_problem/capa/static/js/capa/symbolic_mathjax_preprocessor.js +35 -0
- xblock_problem/capa/static/js/vendor/CodeMirror/octave.js +118 -0
- xblock_problem/capa/templates/annotationinput.html +61 -0
- xblock_problem/capa/templates/chemicalequationinput.html +19 -0
- xblock_problem/capa/templates/choicegroup.html +41 -0
- xblock_problem/capa/templates/choicetext.html +61 -0
- xblock_problem/capa/templates/clarification.html +10 -0
- xblock_problem/capa/templates/codeinput.html +31 -0
- xblock_problem/capa/templates/crystallography.html +29 -0
- xblock_problem/capa/templates/designprotein2dinput.html +25 -0
- xblock_problem/capa/templates/drag_and_drop_input.html +27 -0
- xblock_problem/capa/templates/editageneinput.html +32 -0
- xblock_problem/capa/templates/editamolecule.html +32 -0
- xblock_problem/capa/templates/filesubmission.html +16 -0
- xblock_problem/capa/templates/formulaequationinput.html +29 -0
- xblock_problem/capa/templates/imageinput.html +33 -0
- xblock_problem/capa/templates/jsinput.html +42 -0
- xblock_problem/capa/templates/mathstring.html +8 -0
- xblock_problem/capa/templates/matlabinput.html +121 -0
- xblock_problem/capa/templates/optioninput.html +20 -0
- xblock_problem/capa/templates/problem.html +154 -0
- xblock_problem/capa/templates/problem_ajax.html +16 -0
- xblock_problem/capa/templates/problem_notifications.html +19 -0
- xblock_problem/capa/templates/schematicinput.html +18 -0
- xblock_problem/capa/templates/solutionspan.html +3 -0
- xblock_problem/capa/templates/status_span.html +12 -0
- xblock_problem/capa/templates/textline.html +39 -0
- xblock_problem/capa/templates/vsepr_input.html +38 -0
- xblock_problem/capa/testing/__init__.py +7 -0
- xblock_problem/capa/testing/codejail.py +31 -0
- xblock_problem/capa/testing/response_xml_factory.py +934 -0
- xblock_problem/capa/util.py +252 -0
- xblock_problem/capa/xqueue_interface.py +185 -0
- xblock_problem/capa/xqueue_submission.py +111 -0
- xblock_problem/conf/locale/__init__.py +0 -0
- xblock_problem/conf/locale/config.yaml +93 -0
- xblock_problem/markup.py +33 -0
- xblock_problem/public/css/ProblemBlockDisplay.css +2306 -0
- xblock_problem/public/js/ProblemBlockDisplay.js +1 -0
- xblock_problem/stringify.py +33 -0
- xblock_problem/xmlparser.py +146 -0
- xblock_video/.tx/config +8 -0
- xblock_video/__init__.py +5 -0
- xblock_video/ajax_handler_mixin.py +52 -0
- xblock_video/block.py +1184 -0
- xblock_video/bumper_utils.py +147 -0
- xblock_video/cache_utils.py +97 -0
- xblock_video/conf/locale/__init__.py +0 -0
- xblock_video/conf/locale/config.yaml +93 -0
- xblock_video/constants.py +17 -0
- xblock_video/exceptions.py +11 -0
- xblock_video/mixin.py +58 -0
- xblock_video/public/css/video.css +1260 -0
- xblock_video/public/js/video-xblock.js +2 -0
- xblock_video/studio_metadata_mixin.py +166 -0
- xblock_video/templates/video.html +213 -0
- xblock_video/validation.py +129 -0
- xblock_video/video_handlers.py +514 -0
- xblock_video/video_static_content_utils.py +49 -0
- xblock_video/video_transcripts_utils.py +236 -0
- xblock_video/video_utils.py +178 -0
- xblock_video/video_xfields.py +229 -0
- xblock_word_cloud/.tx/config +8 -0
- xblock_word_cloud/__init__.py +3 -0
- xblock_word_cloud/block.py +295 -0
- xblock_word_cloud/conf/locale/__init__.py +0 -0
- xblock_word_cloud/conf/locale/config.yaml +93 -0
- xblock_word_cloud/static/css/word_cloud.css +29 -0
- xblock_word_cloud/static/js/src/d3.layout.cloud.js +434 -0
- xblock_word_cloud/static/js/src/d3.min.js +37 -0
- xblock_word_cloud/static/js/src/html_utils.js +75 -0
- xblock_word_cloud/static/js/src/word_cloud.js +289 -0
- xblock_word_cloud/templates/word_cloud.html +50 -0
- xblocks_core/__init__.py +11 -0
- xblocks_core/legacy_utils/__init__.py +6 -0
- xblocks_core/legacy_utils/xml_utils.py +584 -0
- xblocks_core-2.0.0.dist-info/METADATA +366 -0
- xblocks_core-2.0.0.dist-info/RECORD +261 -0
- xblocks_core-2.0.0.dist-info/WHEEL +5 -0
- xblocks_core-2.0.0.dist-info/entry_points.txt +18 -0
- xblocks_core-2.0.0.dist-info/licenses/LICENSE.txt +664 -0
- xblocks_core-2.0.0.dist-info/top_level.txt +10 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AnnotatableXBlock allows instructors to add interactive annotations to course content.
|
|
3
|
+
Annotations can have configurable attributes such as title, body, problem index, and highlight color.
|
|
4
|
+
This block enhances the learning experience by enabling students to view embedded comments, questions, or explanations.
|
|
5
|
+
The block supports internationalization (i18n) for multilingual courses.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import textwrap
|
|
10
|
+
import uuid
|
|
11
|
+
|
|
12
|
+
import markupsafe
|
|
13
|
+
from django.utils.translation import gettext_noop as _
|
|
14
|
+
from lxml import etree
|
|
15
|
+
from web_fragments.fragment import Fragment
|
|
16
|
+
from xblock.core import XBlock
|
|
17
|
+
from xblock.fields import Scope, String, XMLString
|
|
18
|
+
from xblock.utils.resources import ResourceLoader
|
|
19
|
+
|
|
20
|
+
from xblocks_core.legacy_utils.xml_utils import LegacyXmlMixin
|
|
21
|
+
|
|
22
|
+
log = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
resource_loader = ResourceLoader(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SerializationError(Exception):
|
|
28
|
+
"""
|
|
29
|
+
Thrown when a module cannot be exported to XML
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, location, msg):
|
|
33
|
+
super().__init__(msg)
|
|
34
|
+
self.location = location
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@XBlock.needs("i18n")
|
|
38
|
+
class AnnotatableBlock(LegacyXmlMixin, XBlock):
|
|
39
|
+
"""
|
|
40
|
+
AnnotatableXBlock allows instructors to create annotated content that students can view interactively.
|
|
41
|
+
Annotations can be styled and customized, with internationalization support for multilingual environments.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
# Indicates that this XBlock has been extracted from edx-platform.
|
|
45
|
+
is_extracted = True
|
|
46
|
+
|
|
47
|
+
display_name = String(
|
|
48
|
+
display_name=_("Display Name"),
|
|
49
|
+
help=_("The display name for this component."),
|
|
50
|
+
scope=Scope.settings,
|
|
51
|
+
default=_("Annotation"),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
data = XMLString(
|
|
55
|
+
help=_("XML data for the annotation"),
|
|
56
|
+
scope=Scope.content,
|
|
57
|
+
default=textwrap.dedent(
|
|
58
|
+
markupsafe.Markup(
|
|
59
|
+
"""
|
|
60
|
+
<annotatable>
|
|
61
|
+
<instructions>
|
|
62
|
+
<p>Enter your (optional) instructions for the exercise in HTML format.</p>
|
|
63
|
+
<p>Annotations are specified by an <code>{}annotation{}</code> tag which may
|
|
64
|
+
may have the following attributes:</p>
|
|
65
|
+
<ul class="instructions-template">
|
|
66
|
+
<li><code>title</code> (optional). Title of the annotation. Defaults to
|
|
67
|
+
<i>Commentary</i> if omitted.</li>
|
|
68
|
+
<li><code>body</code> (<b>required</b>). Text of the annotation.</li>
|
|
69
|
+
<li><code>problem</code> (optional). Numeric index of the problem
|
|
70
|
+
associated with this annotation. This is a zero-based index, so the first
|
|
71
|
+
problem on the page would have <code>problem="0"</code>.</li>
|
|
72
|
+
<li><code>highlight</code> (optional). Possible values: yellow, red,
|
|
73
|
+
orange, green, blue, or purple. Defaults to yellow if this attribute is
|
|
74
|
+
omitted.</li>
|
|
75
|
+
</ul>
|
|
76
|
+
</instructions>
|
|
77
|
+
<p>Add your HTML with annotation spans here.</p>
|
|
78
|
+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
|
79
|
+
<annotation title="My title" body="My comment" highlight="yellow" problem="0">
|
|
80
|
+
Ut sodales laoreet est, egestas gravida felis egestas nec.</annotation> Aenean
|
|
81
|
+
at volutpat erat. Cras commodo viverra nibh in aliquam.</p>
|
|
82
|
+
<p>Nulla facilisi. <annotation body="Basic annotation example." problem="1">
|
|
83
|
+
Pellentesque id vestibulum libero.</annotation> Suspendisse potenti. Morbi
|
|
84
|
+
scelerisque nisi vitae felis dictum mattis. Nam sit amet magna elit. Nullam
|
|
85
|
+
volutpat cursus est, sit amet sagittis odio vulputate et. Curabitur euismod, orci
|
|
86
|
+
in vulputate imperdiet, augue lorem tempor purus, id aliquet augue turpis a est.
|
|
87
|
+
Aenean a sagittis libero. Praesent fringilla pretium magna, non condimentum risus
|
|
88
|
+
elementum nec. Pellentesque faucibus elementum pharetra. Pellentesque vitae metus
|
|
89
|
+
eros.</p>
|
|
90
|
+
</annotatable>
|
|
91
|
+
"""
|
|
92
|
+
).format(markupsafe.escape("<"), markupsafe.escape(">"))
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# List of supported highlight colors for annotations
|
|
97
|
+
HIGHLIGHT_COLORS = ["yellow", "orange", "purple", "blue", "green"]
|
|
98
|
+
|
|
99
|
+
def _get_annotation_class_attr(self, index, el): # pylint: disable=unused-argument
|
|
100
|
+
"""Returns a dict with the CSS class attribute to set on the annotation
|
|
101
|
+
and an XML key to delete from the element.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
attr = {}
|
|
105
|
+
cls = ["annotatable-span", "highlight"]
|
|
106
|
+
highlight_key = "highlight"
|
|
107
|
+
color = el.get(highlight_key)
|
|
108
|
+
|
|
109
|
+
if color is not None:
|
|
110
|
+
if color in self.HIGHLIGHT_COLORS:
|
|
111
|
+
cls.append("highlight-" + color)
|
|
112
|
+
attr["_delete"] = highlight_key
|
|
113
|
+
attr["value"] = " ".join(cls)
|
|
114
|
+
|
|
115
|
+
return {"class": attr}
|
|
116
|
+
|
|
117
|
+
def _get_annotation_data_attr(self, index, el): # pylint: disable=unused-argument
|
|
118
|
+
"""Returns a dict in which the keys are the HTML data attributes
|
|
119
|
+
to set on the annotation element. Each data attribute has a
|
|
120
|
+
corresponding 'value' and (optional) '_delete' key to specify
|
|
121
|
+
an XML attribute to delete.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
data_attrs = {}
|
|
125
|
+
attrs_map = {
|
|
126
|
+
"body": "data-comment-body",
|
|
127
|
+
"title": "data-comment-title",
|
|
128
|
+
"problem": "data-problem-id",
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for xml_key, html_key in attrs_map.items():
|
|
132
|
+
if xml_key in el.attrib:
|
|
133
|
+
value = el.get(xml_key, "")
|
|
134
|
+
data_attrs[html_key] = {"value": value, "_delete": xml_key}
|
|
135
|
+
|
|
136
|
+
return data_attrs
|
|
137
|
+
|
|
138
|
+
def _render_annotation(self, index, el):
|
|
139
|
+
"""Renders an annotation element for HTML output."""
|
|
140
|
+
attr = {}
|
|
141
|
+
attr.update(self._get_annotation_class_attr(index, el))
|
|
142
|
+
attr.update(self._get_annotation_data_attr(index, el))
|
|
143
|
+
|
|
144
|
+
el.tag = "span"
|
|
145
|
+
|
|
146
|
+
for key, value in attr.items():
|
|
147
|
+
el.set(key, value["value"])
|
|
148
|
+
if "_delete" in value and value["_delete"] is not None:
|
|
149
|
+
delete_key = value["_delete"]
|
|
150
|
+
del el.attrib[delete_key]
|
|
151
|
+
|
|
152
|
+
def _render_content(self):
|
|
153
|
+
"""Renders annotatable content with annotation spans and returns HTML."""
|
|
154
|
+
|
|
155
|
+
xmltree = etree.fromstring(self.data)
|
|
156
|
+
self._extract_instructions(xmltree)
|
|
157
|
+
|
|
158
|
+
xmltree.tag = "div"
|
|
159
|
+
if "display_name" in xmltree.attrib:
|
|
160
|
+
del xmltree.attrib["display_name"]
|
|
161
|
+
|
|
162
|
+
index = 0
|
|
163
|
+
for el in xmltree.findall(".//annotation"):
|
|
164
|
+
self._render_annotation(index, el)
|
|
165
|
+
index += 1
|
|
166
|
+
|
|
167
|
+
return etree.tostring(xmltree, encoding="unicode")
|
|
168
|
+
|
|
169
|
+
def _extract_instructions(self, xmltree):
|
|
170
|
+
"""Removes <instructions> from the xmltree and returns them as a string, otherwise None."""
|
|
171
|
+
instructions = xmltree.find("instructions")
|
|
172
|
+
if instructions is not None:
|
|
173
|
+
instructions.tag = "div"
|
|
174
|
+
xmltree.remove(instructions)
|
|
175
|
+
return etree.tostring(instructions, encoding="unicode")
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
def get_html(self):
|
|
179
|
+
"""Returns the HTML representation of the XBlock for student view."""
|
|
180
|
+
return {
|
|
181
|
+
"element_id": uuid.uuid1(0),
|
|
182
|
+
"display_name": self.display_name,
|
|
183
|
+
"instructions_html": self._extract_instructions(etree.fromstring(self.data)),
|
|
184
|
+
"content_html": self._render_content(),
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
def student_view(self, context=None): # pylint: disable=unused-argument
|
|
188
|
+
"""Renders the output that a student will see."""
|
|
189
|
+
frag = Fragment()
|
|
190
|
+
frag.add_content(
|
|
191
|
+
resource_loader.render_django_template(
|
|
192
|
+
"templates/annotatable.html",
|
|
193
|
+
self.get_html(),
|
|
194
|
+
i18n_service=self.runtime.service(self, "i18n"),
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
frag.add_css(resource_loader.load_unicode("static/css/annotatable.css"))
|
|
198
|
+
frag.add_javascript(resource_loader.load_unicode("static/js/src/annotatable.js"))
|
|
199
|
+
frag.initialize_js("Annotatable")
|
|
200
|
+
return frag
|
|
201
|
+
|
|
202
|
+
def studio_view(self, context=None): # pylint: disable=unused-argument
|
|
203
|
+
"""Return the studio view."""
|
|
204
|
+
frag = Fragment()
|
|
205
|
+
frag.add_content(
|
|
206
|
+
resource_loader.render_django_template(
|
|
207
|
+
"templates/annotatable_editor.html",
|
|
208
|
+
{
|
|
209
|
+
"data": self.data,
|
|
210
|
+
},
|
|
211
|
+
i18n_service=self.runtime.service(self, "i18n"),
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
frag.add_css(resource_loader.load_unicode("static/css/annotatable_editor.css"))
|
|
216
|
+
frag.add_javascript(resource_loader.load_unicode("static/js/src/annotatable_editor.js"))
|
|
217
|
+
frag.initialize_js("XMLEditingDescriptor")
|
|
218
|
+
return frag
|
|
219
|
+
|
|
220
|
+
@XBlock.json_handler
|
|
221
|
+
def submit_studio_edits(self, data, suffix=""): # pylint: disable=unused-argument
|
|
222
|
+
"""AJAX handler for saving the studio edits."""
|
|
223
|
+
display_name = data.get("display_name")
|
|
224
|
+
xml_data = data.get("data")
|
|
225
|
+
|
|
226
|
+
if display_name is not None:
|
|
227
|
+
self.display_name = display_name
|
|
228
|
+
if xml_data is not None:
|
|
229
|
+
self.data = xml_data
|
|
230
|
+
|
|
231
|
+
return {"result": "success"}
|
|
232
|
+
|
|
233
|
+
@staticmethod
|
|
234
|
+
def workbench_scenarios():
|
|
235
|
+
"""Defines scenarios for displaying the XBlock in the XBlock workbench."""
|
|
236
|
+
return [
|
|
237
|
+
("AnnotatableXBlock", "<_annotatable_extracted/>"),
|
|
238
|
+
(
|
|
239
|
+
"Multiple AnnotatableXBlock",
|
|
240
|
+
"""
|
|
241
|
+
<vertical_demo>
|
|
242
|
+
<_annotatable_extracted/>
|
|
243
|
+
<_annotatable_extracted/>
|
|
244
|
+
<_annotatable_extracted/>
|
|
245
|
+
</vertical_demo>
|
|
246
|
+
""",
|
|
247
|
+
),
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
@classmethod
|
|
251
|
+
def parse_xml_new_runtime(cls, node, runtime, keys):
|
|
252
|
+
"""
|
|
253
|
+
Interpret the parsed XML in `node`, creating a new instance of this
|
|
254
|
+
module.
|
|
255
|
+
"""
|
|
256
|
+
# In the new/openedx_content-based runtime, XModule parsing (from
|
|
257
|
+
# XmlMixin) is disabled, so definition_from_xml will not be
|
|
258
|
+
# called, and instead the "normal" XBlock parse_xml will be used.
|
|
259
|
+
# However, it's not compatible with RawMixin, so we implement
|
|
260
|
+
# support here.
|
|
261
|
+
data_field_value = cls.definition_from_xml(node, None)[0]["data"]
|
|
262
|
+
for child in node.getchildren():
|
|
263
|
+
node.remove(child)
|
|
264
|
+
# Get attributes, if any, via normal parse_xml.
|
|
265
|
+
try:
|
|
266
|
+
block = super().parse_xml_new_runtime(node, runtime, keys)
|
|
267
|
+
except AttributeError:
|
|
268
|
+
block = super().parse_xml(node, runtime, keys)
|
|
269
|
+
block.data = data_field_value
|
|
270
|
+
return block
|
|
271
|
+
|
|
272
|
+
@classmethod
|
|
273
|
+
def definition_from_xml(cls, xml_object, system):
|
|
274
|
+
if len(xml_object) == 0 and len(list(xml_object.items())) == 0:
|
|
275
|
+
return {"data": ""}, []
|
|
276
|
+
return {"data": etree.tostring(xml_object, pretty_print=True, encoding="unicode")}, []
|
|
277
|
+
|
|
278
|
+
def definition_to_xml(self, resource_fs):
|
|
279
|
+
"""
|
|
280
|
+
Return an Element if we've kept the import OLX, or None otherwise.
|
|
281
|
+
"""
|
|
282
|
+
# If there's no self.data, it means that an XBlock/XModule originally
|
|
283
|
+
# existed for this data at the time of import/editing, but was later
|
|
284
|
+
# uninstalled. RawDescriptor therefore never got to preserve the
|
|
285
|
+
# original OLX that came in, and we have no idea how it should be
|
|
286
|
+
# serialized for export. It's possible that we could do some smarter
|
|
287
|
+
# fallback here and attempt to extract the data, but it's reasonable
|
|
288
|
+
# and simpler to just skip this node altogether.
|
|
289
|
+
if not self.data:
|
|
290
|
+
log.warning(
|
|
291
|
+
"Could not serialize %s: No XBlock installed for '%s' tag.",
|
|
292
|
+
self.usage_key,
|
|
293
|
+
self.usage_key.block_type,
|
|
294
|
+
)
|
|
295
|
+
return None
|
|
296
|
+
|
|
297
|
+
# Normal case: Just echo back the original OLX we saved.
|
|
298
|
+
try:
|
|
299
|
+
return etree.fromstring(self.data)
|
|
300
|
+
except etree.XMLSyntaxError as err:
|
|
301
|
+
# Can't recover here, so just add some info and
|
|
302
|
+
# re-raise
|
|
303
|
+
lines = self.data.split("\n")
|
|
304
|
+
line, offset = err.position
|
|
305
|
+
context = lines[line - 1][offset - 40 : offset + 40]
|
|
306
|
+
msg = f"Unable to create xml for block {self.usage_key}. Context: '{context}'"
|
|
307
|
+
raise SerializationError(self.usage_key, msg) from err
|
|
File without changes
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Configuration for i18n workflow.
|
|
2
|
+
|
|
3
|
+
locales:
|
|
4
|
+
- en # English - Source Language
|
|
5
|
+
# - am # Amharic
|
|
6
|
+
- ar # Arabic
|
|
7
|
+
# - az # Azerbaijani
|
|
8
|
+
# - bg_BG # Bulgarian (Bulgaria)
|
|
9
|
+
# - bn_BD # Bengali (Bangladesh)
|
|
10
|
+
# - bn_IN # Bengali (India)
|
|
11
|
+
# - bs # Bosnian
|
|
12
|
+
# - ca # Catalan
|
|
13
|
+
# - ca@valencia # Catalan (Valencia)
|
|
14
|
+
# - cs # Czech
|
|
15
|
+
# - cy # Welsh
|
|
16
|
+
# - da # Danish
|
|
17
|
+
# - de_DE # German (Germany)
|
|
18
|
+
# - el # Greek
|
|
19
|
+
# - en_GB # English (United Kingdom)
|
|
20
|
+
# # Don't pull these until we figure out why pages randomly display in these locales,
|
|
21
|
+
# # when the user's browser is in English and the user is not logged in.
|
|
22
|
+
# #- en@lolcat # LOLCAT English
|
|
23
|
+
# #- en@pirate # Pirate English
|
|
24
|
+
- es_419 # Spanish (Latin America)
|
|
25
|
+
# - es_AR # Spanish (Argentina)
|
|
26
|
+
# - es_EC # Spanish (Ecuador)
|
|
27
|
+
# - es_ES # Spanish (Spain)
|
|
28
|
+
# - es_MX # Spanish (Mexico)
|
|
29
|
+
# - es_PE # Spanish (Peru)
|
|
30
|
+
# - et_EE # Estonian (Estonia)
|
|
31
|
+
# - eu_ES # Basque (Spain)
|
|
32
|
+
# - fa # Persian
|
|
33
|
+
# - fa_IR # Persian (Iran)
|
|
34
|
+
# - fi_FI # Finnish (Finland)
|
|
35
|
+
# - fil # Filipino
|
|
36
|
+
- fr # French
|
|
37
|
+
# - gl # Galician
|
|
38
|
+
# - gu # Gujarati
|
|
39
|
+
- he # Hebrew
|
|
40
|
+
- hi # Hindi
|
|
41
|
+
# - hr # Croatian
|
|
42
|
+
# - hu # Hungarian
|
|
43
|
+
# - hy_AM # Armenian (Armenia)
|
|
44
|
+
# - id # Indonesian
|
|
45
|
+
# - it_IT # Italian (Italy)
|
|
46
|
+
# - ja_JP # Japanese (Japan)
|
|
47
|
+
# - kk_KZ # Kazakh (Kazakhstan)
|
|
48
|
+
# - km_KH # Khmer (Cambodia)
|
|
49
|
+
# - kn # Kannada
|
|
50
|
+
- ko_KR # Korean (Korea)
|
|
51
|
+
# - lt_LT # Lithuanian (Lithuania)
|
|
52
|
+
# - ml # Malayalam
|
|
53
|
+
# - mn # Mongolian
|
|
54
|
+
# - mr # Marathi
|
|
55
|
+
# - ms # Malay
|
|
56
|
+
# - nb # Norwegian Bokmål
|
|
57
|
+
# - ne # Nepali
|
|
58
|
+
# - nl_NL # Dutch (Netherlands)
|
|
59
|
+
# - or # Oriya
|
|
60
|
+
# - pl # Polish
|
|
61
|
+
- pt_BR # Portuguese (Brazil)
|
|
62
|
+
# - pt_PT # Portuguese (Portugal)
|
|
63
|
+
# - ro # Romanian
|
|
64
|
+
- ru # Russian
|
|
65
|
+
# - si # Sinhala
|
|
66
|
+
# - sk # Slovak
|
|
67
|
+
# - sl # Slovenian
|
|
68
|
+
# - sq # Albanian
|
|
69
|
+
# - sr # Serbian
|
|
70
|
+
# - sv # Swedish
|
|
71
|
+
# - sw # Swahili
|
|
72
|
+
# - ta # Tamil
|
|
73
|
+
# - te # Telugu
|
|
74
|
+
# - th # Thai
|
|
75
|
+
# - tr_TR # Turkish (Turkey)
|
|
76
|
+
# - uk # Ukranian
|
|
77
|
+
# - ur # Urdu
|
|
78
|
+
# - uz # Uzbek
|
|
79
|
+
# - vi # Vietnamese
|
|
80
|
+
- zh_CN # Chinese (China)
|
|
81
|
+
# - zh_HK # Chinese (Hong Kong)
|
|
82
|
+
# - zh_TW # Chinese (Taiwan)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# The locales used for fake-accented English, for testing.
|
|
86
|
+
dummy_locales:
|
|
87
|
+
- eo
|
|
88
|
+
- rtl # Fake testing language for Arabic
|
|
89
|
+
|
|
90
|
+
# Directories we don't search for strings.
|
|
91
|
+
ignore_dirs:
|
|
92
|
+
- '*/css'
|
|
93
|
+
- 'public/js/translations'
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
@import url("https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,600,700");
|
|
2
|
+
|
|
3
|
+
.annotatable-wrapper {
|
|
4
|
+
position: relative;
|
|
5
|
+
}
|
|
6
|
+
.annotatable-header {
|
|
7
|
+
margin-bottom: 0.5em;
|
|
8
|
+
}
|
|
9
|
+
.annotatable-section {
|
|
10
|
+
position: relative;
|
|
11
|
+
padding: 0.5em 1em;
|
|
12
|
+
border: 1px solid var(--gray-l3, #c8c8c8);
|
|
13
|
+
border-radius: 0.5em;
|
|
14
|
+
margin-bottom: 0.5em;
|
|
15
|
+
}
|
|
16
|
+
.annotatable-section.shaded {
|
|
17
|
+
background-color: #ededed;
|
|
18
|
+
}
|
|
19
|
+
.annotatable-section .annotatable-section-title {
|
|
20
|
+
font-weight: bold;
|
|
21
|
+
}
|
|
22
|
+
.annotatable-section .annotatable-section-title a {
|
|
23
|
+
font-weight: normal;
|
|
24
|
+
}
|
|
25
|
+
.annotatable-section .annotatable-section-body {
|
|
26
|
+
border-top: 1px solid var(--gray-l3, #c8c8c8);
|
|
27
|
+
margin-top: 0.5em;
|
|
28
|
+
padding-top: 0.5em;
|
|
29
|
+
}
|
|
30
|
+
.annotatable-section .annotatable-section-body:after {
|
|
31
|
+
content: "";
|
|
32
|
+
display: table;
|
|
33
|
+
clear: both;
|
|
34
|
+
}
|
|
35
|
+
.annotatable-section ul.instructions-template {
|
|
36
|
+
list-style: disc;
|
|
37
|
+
margin-left: 4em;
|
|
38
|
+
}
|
|
39
|
+
.annotatable-section ul.instructions-template b {
|
|
40
|
+
font-weight: bold;
|
|
41
|
+
}
|
|
42
|
+
.annotatable-section ul.instructions-template i {
|
|
43
|
+
font-style: italic;
|
|
44
|
+
}
|
|
45
|
+
.annotatable-section ul.instructions-template code {
|
|
46
|
+
display: inline;
|
|
47
|
+
white-space: pre;
|
|
48
|
+
font-family: Courier New, monospace;
|
|
49
|
+
}
|
|
50
|
+
.annotatable-toggle {
|
|
51
|
+
position: absolute;
|
|
52
|
+
right: 0;
|
|
53
|
+
margin: 2px 1em 2px 0;
|
|
54
|
+
}
|
|
55
|
+
.annotatable-toggle.expanded::after {
|
|
56
|
+
content: " \2191";
|
|
57
|
+
}
|
|
58
|
+
.annotatable-toggle.collapsed::after {
|
|
59
|
+
content: " \2193";
|
|
60
|
+
}
|
|
61
|
+
.annotatable-span {
|
|
62
|
+
display: inline;
|
|
63
|
+
}
|
|
64
|
+
.annotatable-span.highlight {
|
|
65
|
+
background-color: rgba(255, 255, 10, 0.3);
|
|
66
|
+
}
|
|
67
|
+
.annotatable-span.highlight.selected {
|
|
68
|
+
background-color: rgba(255, 255, 10, 0.9);
|
|
69
|
+
}
|
|
70
|
+
.annotatable-span.highlight-yellow {
|
|
71
|
+
background-color: rgba(255, 255, 10, 0.3);
|
|
72
|
+
}
|
|
73
|
+
.annotatable-span.highlight-yellow.selected {
|
|
74
|
+
background-color: rgba(255, 255, 10, 0.9);
|
|
75
|
+
}
|
|
76
|
+
.annotatable-span.highlight-red {
|
|
77
|
+
background-color: rgba(178, 19, 16, 0.3);
|
|
78
|
+
}
|
|
79
|
+
.annotatable-span.highlight-red.selected {
|
|
80
|
+
background-color: rgba(178, 19, 16, 0.9);
|
|
81
|
+
}
|
|
82
|
+
.annotatable-span.highlight-orange {
|
|
83
|
+
background-color: rgba(255, 165, 0, 0.3);
|
|
84
|
+
}
|
|
85
|
+
.annotatable-span.highlight-orange.selected {
|
|
86
|
+
background-color: rgba(255, 165, 0, 0.9);
|
|
87
|
+
}
|
|
88
|
+
.annotatable-span.highlight-green {
|
|
89
|
+
background-color: rgba(25, 255, 132, 0.3);
|
|
90
|
+
}
|
|
91
|
+
.annotatable-span.highlight-green.selected {
|
|
92
|
+
background-color: rgba(25, 255, 132, 0.9);
|
|
93
|
+
}
|
|
94
|
+
.annotatable-span.highlight-blue {
|
|
95
|
+
background-color: rgba(35, 163, 255, 0.3);
|
|
96
|
+
}
|
|
97
|
+
.annotatable-span.highlight-blue.selected {
|
|
98
|
+
background-color: rgba(35, 163, 255, 0.9);
|
|
99
|
+
}
|
|
100
|
+
.annotatable-span.highlight-purple {
|
|
101
|
+
background-color: rgba(115, 9, 178, 0.3);
|
|
102
|
+
}
|
|
103
|
+
.annotatable-span.highlight-purple.selected {
|
|
104
|
+
background-color: rgba(115, 9, 178, 0.9);
|
|
105
|
+
}
|
|
106
|
+
.annotatable-span.hide {
|
|
107
|
+
cursor: none;
|
|
108
|
+
background-color: inherit;
|
|
109
|
+
}
|
|
110
|
+
.annotatable-span.hide .annotatable-icon {
|
|
111
|
+
display: none;
|
|
112
|
+
}
|
|
113
|
+
.annotatable-span .annotatable-comment {
|
|
114
|
+
display: none;
|
|
115
|
+
}
|
|
116
|
+
.ui-tooltip.qtip.ui-tooltip {
|
|
117
|
+
font-size: 0.875em;
|
|
118
|
+
border: 1px solid #333;
|
|
119
|
+
border-radius: 1em;
|
|
120
|
+
background-color: rgba(0, 0, 0, 0.85);
|
|
121
|
+
color: var(--white, #fff);
|
|
122
|
+
-webkit-font-smoothing: antialiased;
|
|
123
|
+
}
|
|
124
|
+
.ui-tooltip.qtip.ui-tooltip .ui-tooltip-titlebar {
|
|
125
|
+
font-size: 1em;
|
|
126
|
+
color: inherit;
|
|
127
|
+
background-color: transparent;
|
|
128
|
+
padding: calc((var(--baseline, 20px) / 4)) calc((var(--baseline, 20px) / 2));
|
|
129
|
+
border: none;
|
|
130
|
+
}
|
|
131
|
+
.ui-tooltip.qtip.ui-tooltip .ui-tooltip-titlebar .ui-tooltip-title {
|
|
132
|
+
padding: calc((var(--baseline, 20px) / 4)) 0;
|
|
133
|
+
border-bottom: 2px solid #333;
|
|
134
|
+
font-weight: bold;
|
|
135
|
+
}
|
|
136
|
+
.ui-tooltip.qtip.ui-tooltip .ui-tooltip-titlebar .ui-tooltip-icon {
|
|
137
|
+
right: 10px;
|
|
138
|
+
background: #333;
|
|
139
|
+
}
|
|
140
|
+
.ui-tooltip.qtip.ui-tooltip .ui-tooltip-titlebar .ui-state-hover {
|
|
141
|
+
color: inherit;
|
|
142
|
+
border: 1px solid var(--gray-l3, #c8c8c8);
|
|
143
|
+
}
|
|
144
|
+
.ui-tooltip.qtip.ui-tooltip .ui-tooltip-content {
|
|
145
|
+
color: inherit;
|
|
146
|
+
font-size: 0.875em;
|
|
147
|
+
text-align: left;
|
|
148
|
+
font-weight: 400;
|
|
149
|
+
padding: 0 calc((var(--baseline, 20px) / 2)) calc((var(--baseline, 20px) / 2)) calc((var(--baseline, 20px) / 2));
|
|
150
|
+
background-color: transparent;
|
|
151
|
+
border-color: transparent;
|
|
152
|
+
}
|
|
153
|
+
.ui-tooltip.qtip.ui-tooltip p {
|
|
154
|
+
color: inherit;
|
|
155
|
+
line-height: normal;
|
|
156
|
+
}
|
|
157
|
+
.ui-tooltip.qtip.ui-tooltip-annotatable {
|
|
158
|
+
max-width: 375px;
|
|
159
|
+
}
|
|
160
|
+
.ui-tooltip.qtip.ui-tooltip-annotatable .ui-tooltip-content {
|
|
161
|
+
padding: 0 calc((var(--baseline, 20px) / 2));
|
|
162
|
+
}
|
|
163
|
+
.ui-tooltip.qtip.ui-tooltip-annotatable .ui-tooltip-content .annotatable-comment {
|
|
164
|
+
display: block;
|
|
165
|
+
margin: 0 0 calc((var(--baseline, 20px) / 2)) 0;
|
|
166
|
+
max-height: 225px;
|
|
167
|
+
overflow: auto;
|
|
168
|
+
line-height: normal;
|
|
169
|
+
}
|
|
170
|
+
.ui-tooltip.qtip.ui-tooltip-annotatable .ui-tooltip-content .annotatable-reply {
|
|
171
|
+
display: block;
|
|
172
|
+
border-top: 2px solid #333;
|
|
173
|
+
padding: calc((var(--baseline, 20px) / 4)) 0;
|
|
174
|
+
margin: 0;
|
|
175
|
+
text-align: center;
|
|
176
|
+
}
|
|
177
|
+
.ui-tooltip.qtip.ui-tooltip-annotatable::after {
|
|
178
|
+
content: '';
|
|
179
|
+
display: inline-block;
|
|
180
|
+
position: absolute;
|
|
181
|
+
bottom: -20px;
|
|
182
|
+
left: 50%;
|
|
183
|
+
height: 0;
|
|
184
|
+
width: 0;
|
|
185
|
+
margin-left: calc(-1 * (var(--baseline, 20px) / 4));
|
|
186
|
+
border: 10px solid transparent;
|
|
187
|
+
border-top-color: rgba(0, 0, 0, 0.85);
|
|
188
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
.wrapper-comp-editor {
|
|
2
|
+
display: block;
|
|
3
|
+
}
|
|
4
|
+
.wrapper-comp-editor.is-inactive {
|
|
5
|
+
display: none;
|
|
6
|
+
}
|
|
7
|
+
.wrapper-comp-editor.latex-problem {
|
|
8
|
+
margin-top: 50px;
|
|
9
|
+
}
|
|
10
|
+
div.wrapper-comp-editor.is-inactive ~ div.launch-latex-compiler {
|
|
11
|
+
display: none;
|
|
12
|
+
}
|