chore: remove legacy problem studio view (#37795)
* fix: remove legacy problem studio view and resource templates
This commit is contained in:
@@ -1450,8 +1450,6 @@ class ContentStoreTest(ContentStoreTestCase):
|
||||
problem_loc = UsageKey.from_string(payload['locator'])
|
||||
problem = self.store.get_item(problem_loc)
|
||||
self.assertIsInstance(problem, ProblemBlock, "New problem is not a ProblemBlock")
|
||||
context = problem.get_context()
|
||||
self.assertIn('markdown', context, "markdown is missing from context")
|
||||
self.assertNotIn('markdown', problem.editable_metadata_fields, "Markdown slipped into the editable metadata fields") # lint-amnesty, pylint: disable=line-too-long
|
||||
|
||||
def test_cms_imported_course_walkthrough(self):
|
||||
|
||||
@@ -20,23 +20,9 @@ class TemplateTests(ModuleStoreTestCase):
|
||||
self.assertIsNotNone(found.get('course'))
|
||||
self.assertIsNotNone(found.get('about'))
|
||||
self.assertIsNotNone(found.get('html'))
|
||||
self.assertIsNotNone(found.get('problem'))
|
||||
self.assertEqual(len(found.get('course')), 0)
|
||||
self.assertEqual(len(found.get('about')), 1)
|
||||
self.assertGreaterEqual(len(found.get('html')), 2)
|
||||
self.assertGreaterEqual(len(found.get('problem')), 10)
|
||||
dropdown = None
|
||||
for template in found['problem']:
|
||||
self.assertIn('metadata', template)
|
||||
self.assertIn('display_name', template['metadata'])
|
||||
if template['metadata']['display_name'] == 'Dropdown':
|
||||
dropdown = template
|
||||
break
|
||||
self.assertIsNotNone(dropdown)
|
||||
self.assertIn('markdown', dropdown['metadata'])
|
||||
self.assertIn('data', dropdown)
|
||||
self.assertRegex(dropdown['metadata']['markdown'], r'.*dropdown problems.*')
|
||||
self.assertRegex(dropdown['data'], r'<problem>\s*<optionresponse>\s*<p>.*dropdown problems.*')
|
||||
|
||||
def test_get_some_templates(self):
|
||||
course = CourseFactory.create()
|
||||
|
||||
@@ -123,25 +123,6 @@ def use_video_gallery_flow():
|
||||
return ENABLE_VIDEO_GALLERY_FLOW_FLAG.is_enabled()
|
||||
|
||||
|
||||
# .. toggle_name: legacy_studio.problem_editor
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Temporarily fall back to the old Problem component (a.k.a. CAPA/problem block) editor.
|
||||
# .. toggle_use_cases: temporary
|
||||
# .. toggle_creation_date: 2025-03-14
|
||||
# .. toggle_target_removal_date: 2025-09-14
|
||||
# .. toggle_tickets: https://github.com/openedx/edx-platform/issues/36275
|
||||
# .. toggle_warning: In Ulmo, this toggle will be removed. Only the new (React-based) experience will be available.
|
||||
LEGACY_STUDIO_PROBLEM_EDITOR = CourseWaffleFlag('legacy_studio.problem_editor', __name__)
|
||||
|
||||
|
||||
def use_new_problem_editor(course_key):
|
||||
"""
|
||||
Returns a boolean if new problem editor is enabled
|
||||
"""
|
||||
return not LEGACY_STUDIO_PROBLEM_EDITOR.is_enabled(course_key)
|
||||
|
||||
|
||||
# .. toggle_name: contentstore.individualize_anonymous_user_id
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
# .. toggle_default: False
|
||||
|
||||
@@ -33,7 +33,6 @@ from cms.djangoapps.contentstore.helpers import (
|
||||
from cms.djangoapps.contentstore.toggles import (
|
||||
libraries_v1_enabled,
|
||||
libraries_v2_enabled,
|
||||
use_new_problem_editor,
|
||||
use_new_unit_page,
|
||||
)
|
||||
from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import load_services_for_studio
|
||||
@@ -368,16 +367,14 @@ def get_component_templates(courselike, library=False): # lint-amnesty, pylint:
|
||||
)
|
||||
)
|
||||
|
||||
#If using new problem editor, we select problem type inside the editor
|
||||
# because of this, we only show one problem.
|
||||
if category == 'problem' and use_new_problem_editor(courselike.context_key):
|
||||
if category == 'problem':
|
||||
templates_for_category = [
|
||||
template for template in templates_for_category if template['boilerplate_name'] == 'blank_common.yaml'
|
||||
]
|
||||
|
||||
# Add any advanced problem types. Note that these are different xblocks being stored as Advanced Problems,
|
||||
# currently not supported in libraries .
|
||||
if category == 'problem' and not library and not use_new_problem_editor(courselike.context_key):
|
||||
if category == 'problem' and not library:
|
||||
disabled_block_names = [block.name for block in disabled_xblocks()]
|
||||
advanced_problem_types = [advanced_problem_type for advanced_problem_type in ADVANCED_PROBLEM_TYPES
|
||||
if advanced_problem_type['component'] not in disabled_block_names]
|
||||
|
||||
@@ -13,7 +13,6 @@ from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from django.test.utils import override_settings
|
||||
from edx_toggles.toggles.testutils import override_waffle_flag
|
||||
from openedx.core.djangoapps.video_config.toggles import PUBLIC_VIDEO_SHARE
|
||||
from openedx_events.content_authoring.data import DuplicatedXBlockData
|
||||
from openedx_events.content_authoring.signals import XBLOCK_DUPLICATED
|
||||
@@ -23,7 +22,6 @@ from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.asides import AsideUsageKeyV2
|
||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
from pyquery import PyQuery
|
||||
from pytz import UTC
|
||||
from bs4 import BeautifulSoup
|
||||
from web_fragments.fragment import Fragment
|
||||
@@ -57,7 +55,6 @@ from xmodule.partitions.partitions import (
|
||||
from xmodule.partitions.tests.test_partitions import MockPartitionService
|
||||
from xmodule.x_module import STUDENT_VIEW, STUDIO_VIEW
|
||||
|
||||
from cms.djangoapps.contentstore import toggles
|
||||
from cms.djangoapps.contentstore.tests.utils import CourseTestCase
|
||||
from cms.djangoapps.contentstore.utils import (
|
||||
reverse_course_url,
|
||||
@@ -229,7 +226,6 @@ class GetItemTest(ItemTest):
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=child_vertical_usage_key,
|
||||
category="problem",
|
||||
boilerplate="multiplechoice.yaml",
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -258,7 +254,6 @@ class GetItemTest(ItemTest):
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=wrapper_usage_key,
|
||||
category="problem",
|
||||
boilerplate="multiplechoice.yaml",
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@@ -286,7 +281,6 @@ class GetItemTest(ItemTest):
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=child_vertical_usage_key,
|
||||
category="problem",
|
||||
boilerplate="multiplechoice.yaml",
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
usage_key = self.response_usage_key(resp)
|
||||
@@ -311,18 +305,13 @@ class GetItemTest(ItemTest):
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=split_test_usage_key,
|
||||
category="html",
|
||||
boilerplate="announcement.yaml",
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=split_test_usage_key,
|
||||
category="html",
|
||||
boilerplate="latex_html.yaml",
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
html, __ = self._get_container_preview(split_test_usage_key)
|
||||
self.assertIn("Announcement", html)
|
||||
self.assertIn("LaTeX", html)
|
||||
|
||||
def test_split_test_edited(self):
|
||||
"""
|
||||
@@ -608,33 +597,12 @@ class TestCreateItem(ItemTest):
|
||||
course = self.get_item_from_modulestore(self.usage_key)
|
||||
self.assertIn(chap_usage_key, course.children)
|
||||
|
||||
# use default display name
|
||||
resp = self.create_xblock(parent_usage_key=chap_usage_key, category="vertical")
|
||||
vert_usage_key = self.response_usage_key(resp)
|
||||
|
||||
# create problem w/ boilerplate
|
||||
template_id = "multiplechoice.yaml"
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=vert_usage_key, category="problem", boilerplate=template_id
|
||||
)
|
||||
prob_usage_key = self.response_usage_key(resp)
|
||||
problem = self.get_item_from_modulestore(prob_usage_key)
|
||||
# check against the template
|
||||
course = CourseFactory.create()
|
||||
problem_block = BlockFactory.create(category="problem", parent_location=course.location)
|
||||
template = problem_block.get_template(template_id)
|
||||
self.assertEqual(problem.data, template["data"])
|
||||
self.assertEqual(problem.display_name, template["metadata"]["display_name"])
|
||||
self.assertEqual(problem.markdown, template["metadata"]["markdown"])
|
||||
|
||||
def test_create_block_negative(self):
|
||||
"""
|
||||
Negative tests for create_item
|
||||
"""
|
||||
# non-existent boilerplate: creates a default
|
||||
resp = self.create_xblock(
|
||||
category="problem", boilerplate="nosuchboilerplate.yaml"
|
||||
)
|
||||
resp = self.create_xblock(category="problem")
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def test_create_with_future_date(self):
|
||||
@@ -836,7 +804,6 @@ class TestDuplicateItem(ItemTest, DuplicateHelper, OpenEdxEventsTestMixin):
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=self.vert_usage_key,
|
||||
category="problem",
|
||||
boilerplate="multiplechoice.yaml",
|
||||
)
|
||||
self.problem_usage_key = self.response_usage_key(resp)
|
||||
|
||||
@@ -936,19 +903,6 @@ class TestDuplicateItem(ItemTest, DuplicateHelper, OpenEdxEventsTestMixin):
|
||||
self.assertEqual(duplicated_item.display_name, expected_name)
|
||||
return usage_key
|
||||
|
||||
# Display name comes from template.
|
||||
dupe_usage_key = verify_name(
|
||||
self.problem_usage_key,
|
||||
self.vert_usage_key,
|
||||
"Duplicate of 'Multiple Choice'",
|
||||
)
|
||||
# Test dupe of dupe.
|
||||
verify_name(
|
||||
dupe_usage_key,
|
||||
self.vert_usage_key,
|
||||
"Duplicate of 'Duplicate of 'Multiple Choice''",
|
||||
)
|
||||
|
||||
# Uses default display_name of 'Text' from HTML component.
|
||||
verify_name(self.html_usage_key, self.vert_usage_key, "Duplicate of 'Text'")
|
||||
|
||||
@@ -1847,7 +1801,6 @@ class TestDuplicateItemWithAsides(ItemTest, DuplicateHelper):
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=self.seq_usage_key,
|
||||
category="problem",
|
||||
boilerplate="multiplechoice.yaml",
|
||||
)
|
||||
self.problem_usage_key = self.response_usage_key(resp)
|
||||
|
||||
@@ -1930,11 +1883,9 @@ class TestEditItemSetup(ItemTest):
|
||||
self.seq2_update_url = reverse_usage_url("xblock_handler", self.seq2_usage_key)
|
||||
|
||||
# create problem w/ boilerplate
|
||||
template_id = "multiplechoice.yaml"
|
||||
resp = self.create_xblock(
|
||||
parent_usage_key=self.seq_usage_key,
|
||||
category="problem",
|
||||
boilerplate=template_id,
|
||||
)
|
||||
self.problem_usage_key = self.response_usage_key(resp)
|
||||
self.problem_update_url = reverse_usage_url(
|
||||
@@ -1965,19 +1916,6 @@ class TestEditItem(TestEditItemSetup):
|
||||
problem = self.get_item_from_modulestore(self.problem_usage_key)
|
||||
self.assertEqual(problem.rerandomize, 'never')
|
||||
|
||||
def test_null_field(self):
|
||||
"""
|
||||
Sending null in for a field 'deletes' it
|
||||
"""
|
||||
problem = self.get_item_from_modulestore(self.problem_usage_key)
|
||||
self.assertIsNotNone(problem.markdown)
|
||||
self.client.ajax_post(
|
||||
self.problem_update_url,
|
||||
data={'nullout': ['markdown']}
|
||||
)
|
||||
problem = self.get_item_from_modulestore(self.problem_usage_key)
|
||||
self.assertIsNone(problem.markdown)
|
||||
|
||||
def test_date_fields(self):
|
||||
"""
|
||||
Test setting due & start dates on sequential
|
||||
@@ -2427,28 +2365,6 @@ class TestEditItem(TestEditItemSetup):
|
||||
) # See xmodule/fields.py
|
||||
|
||||
|
||||
class TestEditItemSplitMongo(TestEditItemSetup):
|
||||
"""
|
||||
Tests for EditItem running on top of the SplitMongoModuleStore.
|
||||
"""
|
||||
|
||||
def test_editing_view_wrappers(self):
|
||||
"""
|
||||
Verify that the editing view only generates a single wrapper, no matter how many times it's loaded
|
||||
|
||||
Exposes: PLAT-417
|
||||
"""
|
||||
view_url = reverse_usage_url(
|
||||
"xblock_view_handler", self.problem_usage_key, {"view_name": STUDIO_VIEW}
|
||||
)
|
||||
|
||||
for __ in range(3):
|
||||
resp = self.client.get(view_url, HTTP_ACCEPT="application/json")
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
content = json.loads(resp.content.decode("utf-8"))
|
||||
self.assertEqual(len(PyQuery(content["html"])(f".xblock-{STUDIO_VIEW}")), 1)
|
||||
|
||||
|
||||
class TestEditSplitModule(ItemTest):
|
||||
"""
|
||||
Tests around editing instances of the split_test block.
|
||||
@@ -2864,7 +2780,6 @@ class TestComponentHandler(TestCase):
|
||||
assert mocked_get_aside_from_xblock.called is is_get_aside_called
|
||||
|
||||
|
||||
@override_waffle_flag(toggles.LEGACY_STUDIO_PROBLEM_EDITOR, True)
|
||||
class TestComponentTemplates(CourseTestCase):
|
||||
"""
|
||||
Unit tests for the generation of the component templates for a course.
|
||||
@@ -3012,12 +2927,6 @@ class TestComponentTemplates(CourseTestCase):
|
||||
self.course.allow_unsupported_xblocks = True
|
||||
self.templates = get_component_templates(self.course)
|
||||
self._verify_basic_component("video", "Video", "us")
|
||||
problem_templates = self.get_templates_of_type("problem")
|
||||
problem_no_boilerplate = self.get_template(
|
||||
problem_templates, "Blank Problem"
|
||||
)
|
||||
self.assertIsNotNone(problem_no_boilerplate)
|
||||
self.assertEqual("us", problem_no_boilerplate["support_level"])
|
||||
|
||||
# Now fully disable video through XBlockConfiguration
|
||||
XBlockConfiguration.objects.create(name="video", enabled=False)
|
||||
@@ -3061,20 +2970,6 @@ class TestComponentTemplates(CourseTestCase):
|
||||
self.templates = get_component_templates(self.course)
|
||||
self.assertTrue((not any(item.get("category") == "done" for item in self.get_templates_of_type("advanced"))))
|
||||
|
||||
def test_advanced_problems(self):
|
||||
"""
|
||||
Test the handling of advanced problem templates.
|
||||
"""
|
||||
problem_templates = self.get_templates_of_type("problem")
|
||||
circuit_template = self.get_template(
|
||||
problem_templates, "Circuit Schematic Builder"
|
||||
)
|
||||
self.assertIsNotNone(circuit_template)
|
||||
self.assertEqual(circuit_template.get("category"), "problem")
|
||||
self.assertEqual(
|
||||
circuit_template.get("boilerplate_name"), "circuitschematic.yaml"
|
||||
)
|
||||
|
||||
def test_deprecated_no_advance_component_button(self):
|
||||
"""
|
||||
Test that there will be no `Advanced` button on unit page if xblocks have disabled
|
||||
|
||||
@@ -4,41 +4,9 @@ define(['js/models/component_template'],
|
||||
var mockTemplateJSON = {
|
||||
templates: [
|
||||
{
|
||||
category: 'problem',
|
||||
boilerplate_name: 'formularesponse.yaml',
|
||||
display_name: 'Math Expression Input'
|
||||
}, {
|
||||
category: 'problem',
|
||||
boilerplate_name: null,
|
||||
display_name: 'Blank Advanced Problem'
|
||||
}, {
|
||||
category: 'problem',
|
||||
boilerplate_name: 'checkboxes.yaml',
|
||||
display_name: 'Checkboxes'
|
||||
}, {
|
||||
category: 'problem',
|
||||
boilerplate_name: 'multiple_choice.yaml',
|
||||
display_name: 'Multiple Choice'
|
||||
}, {
|
||||
category: 'problem',
|
||||
boilerplate_name: 'drag_and_drop.yaml',
|
||||
display_name: 'Drag and Drop'
|
||||
}, {
|
||||
category: 'problem',
|
||||
boilerplate_name: 'problem_with_hint.yaml',
|
||||
display_name: 'Problem with Adaptive Hint'
|
||||
}, {
|
||||
category: 'problem',
|
||||
boilerplate_name: 'imageresponse.yaml',
|
||||
display_name: 'Image Mapped Input'
|
||||
}, {
|
||||
category: 'openassessment',
|
||||
boilerplate_name: null,
|
||||
display_name: 'Peer Assessment'
|
||||
}, {
|
||||
category: 'problem',
|
||||
boilerplate_name: 'an_easy_problem.yaml',
|
||||
display_name: 'An Easy Problem'
|
||||
}, {
|
||||
category: 'word_cloud',
|
||||
boilerplate_name: null,
|
||||
@@ -69,7 +37,7 @@ define(['js/models/component_template'],
|
||||
} else {
|
||||
// If the first template is blank, make sure that it has the correct category
|
||||
if (!template.boilerplate_name) {
|
||||
expect(template.category).toBe('problem');
|
||||
expect(template.category).toBe('openassessment');
|
||||
}
|
||||
lastTemplate = template;
|
||||
}
|
||||
|
||||
@@ -507,12 +507,11 @@ function($, _, Backbone, gettext, BasePage,
|
||||
const primaryHeader = $(event.target).closest('.xblock-header-primary, .nav-actions');
|
||||
|
||||
var useNewVideoEditor = primaryHeader.attr('use-new-editor-video'),
|
||||
useNewProblemEditor = primaryHeader.attr('use-new-editor-problem'),
|
||||
blockType = primaryHeader.attr('data-block-type');
|
||||
|
||||
if((blockType === 'html')
|
||||
|| (useNewVideoEditor === 'True' && blockType === 'video')
|
||||
|| (useNewProblemEditor === 'True' && blockType === 'problem')
|
||||
|| (blockType === 'problem')
|
||||
) {
|
||||
var destinationUrl = primaryHeader.attr('authoring_MFE_base_url')
|
||||
+ '/' + blockType
|
||||
@@ -1172,8 +1171,7 @@ function($, _, Backbone, gettext, BasePage,
|
||||
|
||||
onNewXBlock: function(xblockElement, scrollOffset, is_duplicate, data) {
|
||||
var useNewVideoEditor = this.$('.xblock-header-primary').attr('use-new-editor-video'),
|
||||
useVideoGalleryFlow = this.$('.xblock-header-primary').attr("use-video-gallery-flow"),
|
||||
useNewProblemEditor = this.$('.xblock-header-primary').attr('use-new-editor-problem');
|
||||
useVideoGalleryFlow = this.$('.xblock-header-primary').attr("use-video-gallery-flow");
|
||||
|
||||
// find the block type in the locator if availible
|
||||
if(data.hasOwnProperty('locator')) {
|
||||
@@ -1183,7 +1181,7 @@ function($, _, Backbone, gettext, BasePage,
|
||||
// open mfe editors for new blocks only and not for content imported from libraries
|
||||
if(!data.hasOwnProperty('upstreamRef') && (blockType.includes('html')
|
||||
|| (useNewVideoEditor === 'True' && blockType.includes('video'))
|
||||
|| (useNewProblemEditor === 'True' && blockType.includes('problem')))
|
||||
|| (blockType.includes('problem')))
|
||||
){
|
||||
if (this.options.isIframeEmbed && (this.isSplitTestContentPage || this.isVerticalContentPage)) {
|
||||
return this.postMessageToParent({
|
||||
|
||||
@@ -13,7 +13,7 @@ from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from cms.djangoapps.contentstore.helpers import xblock_studio_url, xblock_type_display_name
|
||||
from cms.djangoapps.contentstore.toggles import use_new_problem_editor, use_new_video_editor, use_video_gallery_flow
|
||||
from cms.djangoapps.contentstore.toggles import use_new_video_editor, use_video_gallery_flow
|
||||
from cms.djangoapps.contentstore.utils import get_editor_page_base_url
|
||||
from openedx.core.djangolib.js_utils import (
|
||||
dump_js_escaped_json, js_escaped_string
|
||||
@@ -112,7 +112,6 @@ from openedx.core.djangolib.markup import HTML, Text
|
||||
|
||||
<%
|
||||
use_new_editor_video = use_new_video_editor(xblock_locator.course_key)
|
||||
use_new_editor_problem = use_new_problem_editor(xblock_locator.course_key)
|
||||
use_new_video_gallery_flow = use_video_gallery_flow()
|
||||
%>
|
||||
|
||||
@@ -168,7 +167,6 @@ use_new_video_gallery_flow = use_video_gallery_flow()
|
||||
|
||||
<nav class="nav-actions" aria-label="${_('Page Actions')}"
|
||||
use-new-editor-video = ${use_new_editor_video}
|
||||
use-new-editor-problem = ${use_new_editor_problem}
|
||||
use-video-gallery-flow = ${use_new_video_gallery_flow}
|
||||
authoring_MFE_base_url = ${get_editor_page_base_url(xblock_locator.course_key)}
|
||||
data-block-type = ${xblock.scope_ids.block_type}
|
||||
|
||||
@@ -8,13 +8,12 @@ from lms.lib.utils import is_unit
|
||||
from openedx.core.djangolib.js_utils import (
|
||||
dump_js_escaped_json, js_escaped_string
|
||||
)
|
||||
from cms.djangoapps.contentstore.toggles import use_new_problem_editor, use_new_video_editor, use_video_gallery_flow
|
||||
from cms.djangoapps.contentstore.toggles import use_new_video_editor, use_video_gallery_flow
|
||||
from cms.lib.xblock.upstream_sync import UpstreamLink
|
||||
from openedx.core.djangoapps.content_tagging.toggles import is_tagging_feature_disabled
|
||||
%>
|
||||
<%
|
||||
use_new_editor_video = use_new_video_editor(xblock.context_key)
|
||||
use_new_editor_problem = use_new_problem_editor(xblock.context_key)
|
||||
use_new_video_gallery_flow = use_video_gallery_flow()
|
||||
use_tagging = not is_tagging_feature_disabled()
|
||||
xblock_url = xblock_studio_url(xblock)
|
||||
@@ -84,7 +83,6 @@ can_unlink = upstream_info.upstream_ref and not upstream_info.has_top_level_pare
|
||||
% endif
|
||||
"
|
||||
use-new-editor-video = ${use_new_editor_video}
|
||||
use-new-editor-problem = ${use_new_editor_problem}
|
||||
use-video-gallery-flow = ${use_new_video_gallery_flow}
|
||||
authoring_MFE_base_url = ${get_editor_page_base_url(xblock.location.course_key)}
|
||||
data-block-type = ${xblock.scope_ids.block_type}
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
<%! from django.utils.translation import gettext as _ %>
|
||||
<%page expression_filter="h"/>
|
||||
<%namespace name='static' file='../static_content.html'/>
|
||||
|
||||
<% isLaTexProblem='source_code' in editable_metadata_fields and editable_metadata_fields['source_code']['explicitly_set'] and enable_latex_compiler %>
|
||||
|
||||
% if isLaTexProblem:
|
||||
<div class="wrapper-comp-editor latex-problem" id="editor-tab">
|
||||
% else:
|
||||
<div class="wrapper-comp-editor" id="editor-tab">
|
||||
% endif
|
||||
<section class="problem-editor editor">
|
||||
<div class="row">
|
||||
%if enable_markdown:
|
||||
<div class="editor-bar">
|
||||
<ul class="format-buttons">
|
||||
<li>
|
||||
<button type="button" class="header-button" data-tooltip="${_("Heading")}">
|
||||
<span class="problem-editor-icon heading3">
|
||||
<img class="icon" src="${static.url('images/cms-editor_heading.png')}" alt="${_("Insert a heading")}">
|
||||
</span>
|
||||
${_("Heading")}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="multiple-choice-button" data-tooltip="${_("Multiple Choice")}">
|
||||
<span class="problem-editor-icon multiple-choice">
|
||||
<img class="icon" src="${static.url('images/cms-editor_radio.png')}" alt="${_("Add a multiple choice question")}">
|
||||
</span>
|
||||
${_("Multiple Choice")}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="checks-button" data-tooltip="${_("Checkboxes")}">
|
||||
<span class="problem-editor-icon checks">
|
||||
<img class="icon" src="${static.url('images/cms-editor_checkbox.png')}" alt="${_("Add a question with checkboxes")}">
|
||||
</span>
|
||||
${_("Checkboxes")}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="string-button" data-tooltip="${_("Text Input")}">
|
||||
<span class="problem-editor-icon string">
|
||||
<img class="icon" src="${static.url('images/cms-editor_text.png')}" alt="${_("Insert a text response")}">
|
||||
</span>
|
||||
${_("Text Input")}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="number-button" data-tooltip="${_("Numerical Input")}">
|
||||
<span class="problem-editor-icon number">
|
||||
<img class="icon" src="${static.url('images/cms-editor_number.png')}" alt="${_("Insert a numerical response")}">
|
||||
</span>
|
||||
${_("Numerical Input")}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="dropdown-button" data-tooltip="${_("Dropdown")}">
|
||||
<span class="problem-editor-icon dropdown">
|
||||
<img class="icon" src="${static.url('images/cms-editor_dropdown.png')}" alt="${_("Insert a dropdown response")}">
|
||||
</span>
|
||||
${_("Dropdown")}
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="explanation-button" data-tooltip="${_("Explanation")}">
|
||||
<span class="problem-editor-icon explanation">
|
||||
<img class="icon" src="${static.url('images/cms-editor_explanation.png')}" alt="${_("Add an explanation for this question")}">
|
||||
</span>
|
||||
${_("Explanation")}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="editor-tabs">
|
||||
<li><button type="button" class="xml-tab advanced-toggle" data-tab="xml">${_("Advanced Editor")}</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
<textarea class="markdown-box">${markdown}</textarea>
|
||||
<article class="simple-editor-cheatsheet shown">
|
||||
<div class="cheatsheet-wrapper">
|
||||
<div class="row">
|
||||
<h5>${_("Markdown Help")}</h5>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col sample heading-1">
|
||||
<img class="icon" src="${static.url('images/cms-editor_heading.png')}" alt="${_("Insert a heading")}">
|
||||
<h6>${_("Heading")}</h6>
|
||||
</div>
|
||||
<div class="col">
|
||||
<pre><code>H3
|
||||
=====
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col sample multiple-choice">
|
||||
<img class="icon" src="${static.url('images/cms-editor_radio.png')}" alt="${_("Add a multiple choice question")}">
|
||||
<h6>${_("Multiple Choice")}</h6>
|
||||
</div>
|
||||
<div class="col">
|
||||
<pre><code>( ) red
|
||||
( ) green
|
||||
(x) blue</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col sample check-multiple">
|
||||
<img class="icon" src="${static.url('images/cms-editor_checkbox.png')}" alt="${_("Add a question with checkboxes")}">
|
||||
<h6>${_("Checkboxes")}</h6>
|
||||
</div>
|
||||
<div class="col">
|
||||
<pre><code>[x] earth
|
||||
[ ] wind
|
||||
[x] water</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col sample string-response">
|
||||
<img class="icon" src="${static.url('images/cms-editor_text.png')}" alt="${_("Insert a text response")}">
|
||||
<h6>${_("Text Input")}</h6>
|
||||
</div>
|
||||
<div class="col">
|
||||
<pre><code>= dog
|
||||
or= cat
|
||||
or= mouse</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col sample numerical-response">
|
||||
<img class="icon" src="${static.url('images/cms-editor_number.png')}" alt="${_("Insert a numerical response")}">
|
||||
<h6>${_("Numerical Input")}</h6>
|
||||
</div>
|
||||
<div class="col">
|
||||
<pre><code>= 3.14 +- 2%</code></pre>
|
||||
<pre><code>= [3.14, 3.15)</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col sample option-reponse">
|
||||
<img class="icon" src="${static.url('images/cms-editor_dropdown.png')}" alt="${_("Insert a dropdown response")}">
|
||||
<h6>${_("Dropdown")}</h6>
|
||||
</div>
|
||||
<div class="col">
|
||||
<pre><code>[[wrong, (right)]]</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<h6>${_("Label")}</h6>
|
||||
<div class="col">
|
||||
<pre><code>>>What is the capital of Argentina?<<</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col sample explanation">
|
||||
<img class="icon" src="${static.url('images/cms-editor_explanation.png')}" alt="${_("Add an explanation for this question")}">
|
||||
<h6>${_("Explanation")}</h6>
|
||||
</div>
|
||||
<div class="col">
|
||||
<pre><code>[explanation] A short explanation of the answer. [explanation]</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
%endif
|
||||
</div>
|
||||
<textarea class="xml-box" rows="8" cols="40">${data}</textarea>
|
||||
</section>
|
||||
|
||||
<script type="text/template" id="simple-editor-cheatsheet">
|
||||
|
||||
</script>
|
||||
</div>
|
||||
<%include file="metadata-edit.html" />
|
||||
Reference in New Issue
Block a user