From 326f82721e7b7bd37feff3ff5ff25c4d551812b0 Mon Sep 17 00:00:00 2001 From: Arunmozhi Date: Thu, 6 Jan 2022 16:26:11 +0530 Subject: [PATCH] feat: reset a Randomized Content Block via AJAX This makes the reset button to refresh the contents of a Randomized Content Block (RCB) without reloading the full page by fetching a new set of problems in the "reset" response and replacing the DOM contents. The reset button returns the student view as a string and the client uses the HtmlUtils package to replace the contents and reinitializes the XBlock. This allows students to use the RCB as a flash card system. --- .../library_content/public/js/library_content_reset.js | 10 ++++++++-- common/lib/xmodule/xmodule/library_content_module.py | 2 +- .../lib/xmodule/xmodule/tests/test_library_content.py | 8 +++++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js b/common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js index 81eb7d2105e7..e985d3c2a692 100644 --- a/common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js +++ b/common/lib/xmodule/xmodule/assets/library_content/public/js/library_content_reset.js @@ -4,8 +4,14 @@ function LibraryContentReset(runtime, element) { e.preventDefault(); $.post({ url: runtime.handlerUrl(element, 'reset_selected_children'), - success() { - location.reload(); + success(data) { + edx.HtmlUtils.setHtml(element, edx.HtmlUtils.HTML(data)); + // Rebind the reset button for the block + XBlock.initializeBlock(element); + // Render the new set of problems (XBlocks) + $(".xblock", element).each(function(i, child) { + XBlock.initializeBlock(child); + }); }, }); }); diff --git a/common/lib/xmodule/xmodule/library_content_module.py b/common/lib/xmodule/xmodule/library_content_module.py index 29e772f8bee1..5e54ea9b201b 100644 --- a/common/lib/xmodule/xmodule/library_content_module.py +++ b/common/lib/xmodule/xmodule/library_content_module.py @@ -375,7 +375,7 @@ def reset_selected_children(self, _, __): block.save() self.selected = [] - return Response() + return Response(json.dumps(self.student_view({}).content)) def _get_selected_child_blocks(self): """ diff --git a/common/lib/xmodule/xmodule/tests/test_library_content.py b/common/lib/xmodule/xmodule/tests/test_library_content.py index a2d057b984c3..748a962f1d65 100644 --- a/common/lib/xmodule/xmodule/tests/test_library_content.py +++ b/common/lib/xmodule/xmodule/tests/test_library_content.py @@ -4,7 +4,7 @@ Higher-level tests are in `cms/djangoapps/contentstore/tests/test_libraries.py`. """ import ddt -from unittest.mock import Mock, patch +from unittest.mock import MagicMock, Mock, patch from bson.objectid import ObjectId from fs.memoryfs import MemoryFS @@ -405,13 +405,19 @@ def test_reset_selected_children_capa_blocks(self, allow_resetting_children, max self._create_capa_problems() self.lc_block.refresh_children() self.lc_block = self.store.get_item(self.lc_block.location) + # Mock the student view to return an empty dict to be returned as response + self.lc_block.student_view = MagicMock() + self.lc_block.student_view.return_value.content = {} with patch.object(ProblemBlock, 'reset_problem', return_value={'success': True}) as reset_problem: response = self.lc_block.reset_selected_children(None, None) if allow_resetting_children: + self.lc_block.student_view.assert_called_once_with({}) assert reset_problem.call_count == len(self.problem_types) assert response.status_code == status.HTTP_200_OK + assert response.content_type == "text/html" + assert response.body == b"{}" else: reset_problem.assert_not_called() assert response.status_code == status.HTTP_400_BAD_REQUEST