""" Library Sourced Content XBlock """ import logging from copy import copy from mako.template import Template as MakoTemplate from xblock.core import XBlock from xblock.fields import Scope, String, List from xblock.validation import ValidationMessage from xblockutils.resources import ResourceLoader from xblockutils.studio_editable import StudioEditableXBlockMixin from webob import Response from web_fragments.fragment import Fragment from xmodule.studio_editable import StudioEditableBlock as EditableChildrenMixin from xmodule.validation import StudioValidation, StudioValidationMessage log = logging.getLogger(__name__) loader = ResourceLoader(__name__) # Make '_' a no-op so we can scrape strings. Using lambda instead of # `django.utils.translation.ugettext_noop` because Django cannot be imported in this file _ = lambda text: text @XBlock.wants('library_tools') # Only needed in studio class LibrarySourcedBlock(StudioEditableXBlockMixin, EditableChildrenMixin, XBlock): """ Library Sourced Content XBlock Allows copying specific XBlocks from a Blockstore-based content library into a modulestore-based course. The selected blocks are copied and become children of this block. When we implement support for Blockstore-based courses, it's expected we'll use a different mechanism for importing library content into a course. """ display_name = String( help=_("The display name for this component."), default="Library Sourced Content", display_name=_("Display Name"), scope=Scope.content, ) source_block_ids = List( display_name=_("Library Blocks List"), help=_("Enter the IDs of the library XBlocks that you wish to use."), scope=Scope.content, ) editable_fields = ("display_name", "source_block_ids") has_children = True has_author_view = True resources_dir = 'assets/library_source_block' MAX_BLOCKS_ALLOWED = 10 def __str__(self): return f"LibrarySourcedBlock: {self.display_name}" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not self.source_block_ids: self.has_children = False def studio_view(self, context): """ Render a form for editing this XBlock """ fragment = Fragment() static_content = ResourceLoader('common.djangoapps.pipeline_mako').load_unicode('templates/static_content.html') render_react = MakoTemplate(static_content, default_filters=[]).get_def('renderReact') react_content = render_react.render( component="LibrarySourcedBlockPicker", id="library-sourced-block-picker", props={ 'selectedXblocks': self.source_block_ids, } ) fragment.content = loader.render_django_template('templates/library-sourced-block-studio-view.html', { 'react_content': react_content, 'save_url': self.runtime.handler_url(self, 'submit_studio_edits'), }) fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/library_source_block.js')) fragment.initialize_js('LibrarySourceBlockStudioView') return fragment def author_view(self, context): """ Renders the Studio preview view. """ fragment = Fragment() context = {} if not context else copy(context) # Isolate context - without this there are weird bugs in Studio # EditableChildrenMixin.render_children will render HTML that allows instructors to make edits to the children context['can_move'] = False self.render_children(context, fragment, can_reorder=False, can_add=False) return fragment def student_view(self, context): """ Renders the view that learners see. """ result = Fragment() child_frags = self.runtime.render_children(self, context=context) result.add_resources(child_frags) result.add_content('