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,367 @@
|
|
|
1
|
+
function Annotatable(runtime, element) {
|
|
2
|
+
var _debug = false;
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
Selectors for the annotatable xmodule
|
|
6
|
+
*/
|
|
7
|
+
var wrapperSelector = '.annotatable-wrapper';
|
|
8
|
+
var toggleAnnotationsSelector = '.annotatable-toggle-annotations';
|
|
9
|
+
var toggleInstructionsSelector = '.annotatable-toggle-instructions';
|
|
10
|
+
var instructionsSelector = '.annotatable-instructions';
|
|
11
|
+
var spanSelector = '.annotatable-span';
|
|
12
|
+
var replySelector = '.annotatable-reply';
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
Selectors for responding to events from the annotation capa problem type
|
|
16
|
+
*/
|
|
17
|
+
var problemInputSelector = 'div.problem .annotation-input';
|
|
18
|
+
var problemReturnSelector = 'div.problem .annotation-return';
|
|
19
|
+
|
|
20
|
+
var annotationsHidden = false;
|
|
21
|
+
var instructionsHidden = false;
|
|
22
|
+
|
|
23
|
+
var $el = $(element);
|
|
24
|
+
|
|
25
|
+
init();
|
|
26
|
+
|
|
27
|
+
function init() {
|
|
28
|
+
initEvents();
|
|
29
|
+
initTips();
|
|
30
|
+
if (_debug) {
|
|
31
|
+
console.log('Annotatable XBlock Loaded');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function initEvents() {
|
|
36
|
+
annotationsHidden = false;
|
|
37
|
+
instructionsHidden = false;
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
Initialize toggle handlers for the instructions and annotations sections
|
|
41
|
+
*/
|
|
42
|
+
$(toggleAnnotationsSelector).on('click', onClickToggleAnnotations);
|
|
43
|
+
$(toggleInstructionsSelector).on('click', onClickToggleInstructions);
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
Initialize handler for 'reply to annotation' events that scroll to
|
|
47
|
+
the associated problem. The reply buttons are part of the tooltip
|
|
48
|
+
content. It's important that the tooltips be configured to render
|
|
49
|
+
as descendants of the annotation module and *not* the document.body.
|
|
50
|
+
*/
|
|
51
|
+
$el.on('click', replySelector, onClickReply);
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
Initialize handler for 'return to annotation' events triggered from problems.
|
|
55
|
+
1) There are annotationinput capa problems rendered on the page
|
|
56
|
+
2) Each one has an embedded return link (see annotation capa problem template).
|
|
57
|
+
Since the capa problem injects HTML content via AJAX, the best we can do is
|
|
58
|
+
let the click events bubble up to the body and handle them there.
|
|
59
|
+
*/
|
|
60
|
+
$(document).on('click', problemReturnSelector, onClickReturn);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function initTips() {
|
|
64
|
+
/*
|
|
65
|
+
Tooltips are used to display annotations for highlighted text spans
|
|
66
|
+
*/
|
|
67
|
+
$(spanSelector).each(function(index, el) {
|
|
68
|
+
$(el).qtip(getSpanTipOptions(el));
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getSpanTipOptions(el) {
|
|
73
|
+
return {
|
|
74
|
+
content: {
|
|
75
|
+
title: {
|
|
76
|
+
text: makeTipTitle(el),
|
|
77
|
+
},
|
|
78
|
+
text: makeTipContent(el),
|
|
79
|
+
},
|
|
80
|
+
position: {
|
|
81
|
+
/*
|
|
82
|
+
Of tooltip
|
|
83
|
+
*/
|
|
84
|
+
my: 'bottom center',
|
|
85
|
+
/*
|
|
86
|
+
Of target
|
|
87
|
+
*/
|
|
88
|
+
at: 'top center',
|
|
89
|
+
/*
|
|
90
|
+
Where the tooltip was triggered (i.e., the annotation span)
|
|
91
|
+
*/
|
|
92
|
+
target: $(el),
|
|
93
|
+
container: $(wrapperSelector),
|
|
94
|
+
adjust: {
|
|
95
|
+
y: -5,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
show: {
|
|
99
|
+
event: 'click mouseenter',
|
|
100
|
+
solo: true,
|
|
101
|
+
},
|
|
102
|
+
hide: {
|
|
103
|
+
event: 'click mouseleave',
|
|
104
|
+
delay: 500,
|
|
105
|
+
/*
|
|
106
|
+
Don't hide the tooltip if it is moused over
|
|
107
|
+
*/
|
|
108
|
+
fixed: true,
|
|
109
|
+
},
|
|
110
|
+
style: {
|
|
111
|
+
classes: 'ui-tooltip-annotatable',
|
|
112
|
+
},
|
|
113
|
+
events: {
|
|
114
|
+
show: onShowTip,
|
|
115
|
+
move: onMoveTip,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function onClickToggleAnnotations(e) {
|
|
121
|
+
toggleAnnotations();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function onClickToggleInstructions(e) {
|
|
125
|
+
toggleInstructions();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function onClickReply(e) {
|
|
129
|
+
replyTo(e.currentTarget);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function onClickReturn(e) {
|
|
133
|
+
returnFrom(e.currentTarget);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function onShowTip(event, api) {
|
|
137
|
+
if (annotationsHidden) {
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function onMoveTip(event, api, position) {
|
|
143
|
+
/*
|
|
144
|
+
This method handles a vertical positioning bug in Firefox as
|
|
145
|
+
well as an edge case in which a tooltip is displayed above a
|
|
146
|
+
non-overlapping span like this:
|
|
147
|
+
|
|
148
|
+
(( TOOLTIP ))
|
|
149
|
+
\/
|
|
150
|
+
text text text ... text text text ...... <span span span>
|
|
151
|
+
<span span span>
|
|
152
|
+
|
|
153
|
+
The problem is that the tooltip looks disconnected from both spans, so
|
|
154
|
+
we should re-position the tooltip to appear above the span.
|
|
155
|
+
*/
|
|
156
|
+
var tip = api.elements.tooltip;
|
|
157
|
+
var adjustY = (api.options.position && api.options.position.adjust && api.options.position.adjust.y) || 0;
|
|
158
|
+
var container = (api.options.position && api.options.position.container) || $('body');
|
|
159
|
+
var target = api.elements.target;
|
|
160
|
+
var rects = $(target).get(0).getClientRects();
|
|
161
|
+
var isNonOverlapping = rects && rects.length === 2 && rects[0].left > rects[1].right;
|
|
162
|
+
var focusRect;
|
|
163
|
+
|
|
164
|
+
if (isNonOverlapping) {
|
|
165
|
+
/*
|
|
166
|
+
Choose the largest of the two non-overlapping spans and display
|
|
167
|
+
the tooltip above the center of it
|
|
168
|
+
*/
|
|
169
|
+
focusRect = rects[0].width > rects[1].width ? rects[0] : rects[1];
|
|
170
|
+
} else {
|
|
171
|
+
/*
|
|
172
|
+
Always compute the new position because Firefox doesn't
|
|
173
|
+
properly vertically position the tooltip
|
|
174
|
+
*/
|
|
175
|
+
focusRect = rects[0];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
var rectCenter = focusRect.left + focusRect.width / 2;
|
|
179
|
+
var rectTop = focusRect.top;
|
|
180
|
+
var tipWidth = $(tip).width();
|
|
181
|
+
var tipHeight = $(tip).height();
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
Tooltip is positioned relative to its container, so we need to factor in offsets
|
|
185
|
+
*/
|
|
186
|
+
var containerOffset = $(container).offset();
|
|
187
|
+
var offsetLeft = -containerOffset.left;
|
|
188
|
+
var offsetTop = $(document).scrollTop() - containerOffset.top;
|
|
189
|
+
var tipLeft = offsetLeft + rectCenter - tipWidth / 2;
|
|
190
|
+
var tipTop = offsetTop + rectTop - tipHeight + adjustY;
|
|
191
|
+
|
|
192
|
+
/*
|
|
193
|
+
Make sure the new tip position doesn't clip the edges of the screen
|
|
194
|
+
*/
|
|
195
|
+
var winWidth = $(window).width();
|
|
196
|
+
if (tipLeft < offsetLeft) {
|
|
197
|
+
tipLeft = offsetLeft;
|
|
198
|
+
} else if (tipLeft + tipWidth > winWidth + offsetLeft) {
|
|
199
|
+
tipLeft = winWidth + offsetLeft - tipWidth;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/*
|
|
203
|
+
Update the position object (used by qTip2 to show the tip after the move event)
|
|
204
|
+
*/
|
|
205
|
+
$.extend(position, {
|
|
206
|
+
left: tipLeft,
|
|
207
|
+
top: tipTop,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getSpanForProblemReturn(el) {
|
|
212
|
+
var problemId = $(problemReturnSelector).index(el);
|
|
213
|
+
return $(spanSelector).filter("[data-problem-id='" + problemId + "']");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function getProblem(el) {
|
|
217
|
+
var problemId = getProblemId(el);
|
|
218
|
+
return $(problemInputSelector).eq(problemId);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function getProblemId(el) {
|
|
222
|
+
return $(el).data('problem-id');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function toggleAnnotations() {
|
|
226
|
+
annotationsHidden = !annotationsHidden;
|
|
227
|
+
var hide = annotationsHidden;
|
|
228
|
+
toggleAnnotationButtonText(hide);
|
|
229
|
+
toggleSpans(hide);
|
|
230
|
+
toggleTips(hide);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function toggleTips(hide) {
|
|
234
|
+
var visible = findVisibleTips();
|
|
235
|
+
hideTips(visible);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function toggleAnnotationButtonText(hide) {
|
|
239
|
+
var buttonText = hide ? gettext('Show Annotations') : gettext('Hide Annotations');
|
|
240
|
+
$(toggleAnnotationsSelector).text(buttonText);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function toggleInstructions() {
|
|
244
|
+
instructionsHidden = !instructionsHidden;
|
|
245
|
+
var hide = instructionsHidden;
|
|
246
|
+
toggleInstructionsButton(hide);
|
|
247
|
+
toggleInstructionsText(hide);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function toggleInstructionsButton(hide) {
|
|
251
|
+
var txt = hide ? gettext('Expand Instructions') : gettext('Collapse Instructions');
|
|
252
|
+
var cls = hide ? ['expanded', 'collapsed'] : ['collapsed', 'expanded'];
|
|
253
|
+
$(toggleInstructionsSelector).text(txt).removeClass(cls[0]).addClass(cls[1]);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function toggleInstructionsText(hide) {
|
|
257
|
+
var slideMethod = hide ? 'slideUp' : 'slideDown';
|
|
258
|
+
$(instructionsSelector)[slideMethod]();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function toggleSpans(hide) {
|
|
262
|
+
$(spanSelector).toggleClass('hide', hide, 250);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function replyTo(buttonEl) {
|
|
266
|
+
var offset = -20;
|
|
267
|
+
var el = getProblem(buttonEl);
|
|
268
|
+
if (el.length > 0) {
|
|
269
|
+
scrollTo(el, afterScrollToProblem, offset);
|
|
270
|
+
} else if (_debug) {
|
|
271
|
+
console.log('Problem not found. Element:', buttonEl);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function returnFrom(buttonEl) {
|
|
276
|
+
var offset = -200;
|
|
277
|
+
var el = getSpanForProblemReturn(buttonEl);
|
|
278
|
+
if (el.length > 0) {
|
|
279
|
+
scrollTo(el, afterScrollToSpan, offset);
|
|
280
|
+
} else if (_debug) {
|
|
281
|
+
console.log('Span not found. Element:', buttonEl);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function scrollTo(el, after, offset) {
|
|
286
|
+
offset = offset || -20;
|
|
287
|
+
if ($(el).length > 0) {
|
|
288
|
+
$('html,body').scrollTo(el, {
|
|
289
|
+
duration: 500,
|
|
290
|
+
onAfter: _once(function() {
|
|
291
|
+
if (after) {
|
|
292
|
+
after.call(this, el);
|
|
293
|
+
}
|
|
294
|
+
}),
|
|
295
|
+
offset: offset,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function afterScrollToProblem(problemEl) {
|
|
301
|
+
problemEl.effect('highlight', {}, 500);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function afterScrollToSpan(spanEl) {
|
|
305
|
+
spanEl.addClass('selected', 400, 'swing', function() {
|
|
306
|
+
spanEl.removeClass('selected', 400, 'swing');
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function makeTipContent(el) {
|
|
311
|
+
return function(api) {
|
|
312
|
+
var text = $(el).data('comment-body');
|
|
313
|
+
var comment = createComment(text);
|
|
314
|
+
var problemId = getProblemId(el);
|
|
315
|
+
var reply = createReplyLink(problemId);
|
|
316
|
+
return $(comment).add(reply);
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function makeTipTitle(el) {
|
|
321
|
+
return function(api) {
|
|
322
|
+
var title = $(el).data('comment-title');
|
|
323
|
+
return title || gettext('Commentary');
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function createComment(text) {
|
|
328
|
+
return $('<div class="annotatable-comment">' + text + '</div>'); // xss-lint: disable=javascript-concat-html
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function createReplyLink(problemId) {
|
|
332
|
+
var linkText = gettext('Reply to Annotation');
|
|
333
|
+
return $(
|
|
334
|
+
'<a class="annotatable-reply" href="javascript:void(0);" data-problem-id="'
|
|
335
|
+
+ problemId
|
|
336
|
+
+ '">'
|
|
337
|
+
+ linkText
|
|
338
|
+
+ '</a>',
|
|
339
|
+
); // xss-lint: disable=javascript-concat-html
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function findVisibleTips() {
|
|
343
|
+
var visible = [];
|
|
344
|
+
$(spanSelector).each(function(index, el) {
|
|
345
|
+
var api = $(el).qtip('api');
|
|
346
|
+
var tip = $(api && api.elements.tooltip);
|
|
347
|
+
if (tip.is(':visible')) {
|
|
348
|
+
visible.push(el);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
return visible;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function hideTips(elements) {
|
|
355
|
+
$(elements).qtip('hide');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function _once(fn) {
|
|
359
|
+
var done = false;
|
|
360
|
+
return function() {
|
|
361
|
+
if (!done) {
|
|
362
|
+
fn.call(this);
|
|
363
|
+
done = true;
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
function XMLEditingDescriptor(runtime, element) {
|
|
2
|
+
var saveButtonSelector = '.save-button';
|
|
3
|
+
var cancelButtonSelector = '.cancel-button';
|
|
4
|
+
var editBoxSelector = '.edit-box';
|
|
5
|
+
var _debug = false;
|
|
6
|
+
|
|
7
|
+
var el = element;
|
|
8
|
+
|
|
9
|
+
var textarea = $(editBoxSelector, el)[0];
|
|
10
|
+
if (!textarea) {
|
|
11
|
+
console.error('Error: Textarea with class "edit-box" not found.');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var editBox = CodeMirror.fromTextArea(textarea, {
|
|
16
|
+
mode: 'xml',
|
|
17
|
+
lineNumbers: true,
|
|
18
|
+
lineWrapping: true
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
if (_debug) {
|
|
22
|
+
console.log('loaded XMLEditingDescriptor');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function init() {
|
|
26
|
+
initEvents();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function initEvents() {
|
|
30
|
+
$(saveButtonSelector, el).on('click', onClickSave);
|
|
31
|
+
$(cancelButtonSelector, el).on('click', onClickCancel);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function onClickSave(e) {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
submit();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function onClickCancel(e) {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
closeEditor();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function save() {
|
|
45
|
+
return {
|
|
46
|
+
data: editBox.getValue()
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function submit() {
|
|
51
|
+
var handlerUrl = runtime.handlerUrl(el, 'submit_studio_edits');
|
|
52
|
+
runtime.notify('save', {state: 'start', message: 'Saving...'});
|
|
53
|
+
var data = save();
|
|
54
|
+
|
|
55
|
+
$.ajax({
|
|
56
|
+
type: 'POST',
|
|
57
|
+
url: handlerUrl,
|
|
58
|
+
data: JSON.stringify(data),
|
|
59
|
+
dataType: 'json',
|
|
60
|
+
success: function(response) {
|
|
61
|
+
runtime.notify('save', {state: 'end'});
|
|
62
|
+
}
|
|
63
|
+
}).fail(function(jqXHR) {
|
|
64
|
+
var message = 'There was an issue saving the settings. Please try again.';
|
|
65
|
+
runtime.notify('error', {title: 'Unable to save', message: message});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function closeEditor() {
|
|
70
|
+
runtime.notify('cancel', {});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
init();
|
|
74
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
<div class="annotatable-wrapper" id="annotatable_{{ element_id }}">
|
|
3
|
+
<div class="annotatable-header">
|
|
4
|
+
{% if display_name %}<h3 class="hd hd-3 annotatable-title">{{ display_name }}</h3>{% endif %}
|
|
5
|
+
</div>
|
|
6
|
+
{% if instructions_html %}
|
|
7
|
+
<div class="annotatable-section shaded">
|
|
8
|
+
<div class="annotatable-section-title">
|
|
9
|
+
{% trans "Instructions" %}
|
|
10
|
+
<a class="annotatable-toggle annotatable-toggle-instructions expanded"
|
|
11
|
+
href="javascript:void(0)">{% trans "Collapse Instructions" %}</a>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="annotatable-section-body annotatable-instructions">{{ instructions_html|safe }}</div>
|
|
14
|
+
</div>
|
|
15
|
+
{% endif %}
|
|
16
|
+
<div class="annotatable-section">
|
|
17
|
+
<div class="annotatable-section-title">
|
|
18
|
+
{% trans "Guided Discussion" %}
|
|
19
|
+
<a class="annotatable-toggle annotatable-toggle-annotations"
|
|
20
|
+
href="javascript:void(0)">{% trans "Hide Annotations" %}</a>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="annotatable-section-body annotatable-content">{{ content_html|safe }}</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{% load i18n %}
|
|
2
|
+
<div class="editor-with-buttons">
|
|
3
|
+
<div class="wrapper-comp-editor" id="editor-tab">
|
|
4
|
+
<section class="raw-edit">
|
|
5
|
+
<textarea name="data" class="edit-box" rows="8" cols="40">{{ data }}</textarea>
|
|
6
|
+
</section>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="xblock-actions">
|
|
10
|
+
<ul>
|
|
11
|
+
<li class="action-item">
|
|
12
|
+
<a href="#" class="button action-primary save-button">{% trans "Save" %}</a>
|
|
13
|
+
</li>
|
|
14
|
+
|
|
15
|
+
<li class="action-item">
|
|
16
|
+
<a href="#" class="button cancel-button">{% trans "Cancel" %}</a>
|
|
17
|
+
</li>
|
|
18
|
+
</ul>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Django App configuration for the xblocks-core Discussion XBlock.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from django.apps import AppConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DiscussionAppConfig(AppConfig):
|
|
9
|
+
"""
|
|
10
|
+
Configuration for the Discussion XBlock Django application.
|
|
11
|
+
|
|
12
|
+
Why are we registering this as a Django App?
|
|
13
|
+
--------------------------------------------
|
|
14
|
+
By default, Django's template engine (specifically the `app_directories` loader)
|
|
15
|
+
only discovers `templates/` folders that belong to an app listed in `INSTALLED_APPS`.
|
|
16
|
+
|
|
17
|
+
Since XBlocks are inherently isolated components, they are not typically added
|
|
18
|
+
to the LMS/CMS global `INSTALLED_APPS`. As a result, any standard Django templates
|
|
19
|
+
(.html files) inside this block would be invisible to the core Open edX platform
|
|
20
|
+
when it attempts to route or render them natively.
|
|
21
|
+
|
|
22
|
+
Instead of forcing repository consumers to manually modify `lms/envs/common.py`
|
|
23
|
+
or use deployment-specific Tutor plugins to append to `TEMPLATES['DIRS']`, we
|
|
24
|
+
leverage the Open edX Django App Plugin Framework (`plugin_app`). This hook
|
|
25
|
+
dynamically injects this module into `INSTALLED_APPS` at runtime.
|
|
26
|
+
|
|
27
|
+
This automatically exposes our `templates/` directory to the platform natively
|
|
28
|
+
without manual intervention.
|
|
29
|
+
|
|
30
|
+
References:
|
|
31
|
+
|
|
32
|
+
- Open edX Plugin App Framework:
|
|
33
|
+
https://docs.openedx.org/projects/edx-django-utils/en/latest/plugins/how_tos/how_to_create_a_plugin_app.html
|
|
34
|
+
|
|
35
|
+
- Django App Directories Loader:
|
|
36
|
+
https://docs.djangoproject.com/en/stable/ref/templates/api/#django.template.loaders.app_directories.Loader
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
name = "xblock_discussion"
|
|
41
|
+
label = "xblock_discussion"
|
|
42
|
+
verbose_name = "XBlocks Core - Discussion Templates"
|
|
43
|
+
|
|
44
|
+
plugin_app = {
|
|
45
|
+
"settings_config": {
|
|
46
|
+
"lms.djangoapp": {
|
|
47
|
+
"default": "",
|
|
48
|
+
},
|
|
49
|
+
"cms.djangoapp": {
|
|
50
|
+
"default": "",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
}
|