def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): """ Wraps the results of rendering an XBlock view in a div which adds a header and Studio action buttons. """ # Only add the Studio wrapper when on the container page. The "Pages" page will remain as is for now. if not context.get('is_pages_view', None) and view in PREVIEW_VIEWS: root_xblock = context.get('root_xblock') is_root = root_xblock and xblock.location == root_xblock.location is_reorderable = _is_xblock_reorderable(xblock, context) selected_groups_label = get_visibility_partition_info( xblock)['selected_groups_label'] if selected_groups_label: selected_groups_label = _( 'Access restricted to: {list_of_groups}').format( list_of_groups=selected_groups_label) template_context = { 'xblock_context': context, 'xblock': xblock, 'show_preview': context.get('show_preview', True), 'content': frag.content, 'is_root': is_root, 'is_reorderable': is_reorderable, 'can_edit': context.get('can_edit', True), 'can_edit_visibility': context.get('can_edit_visibility', True), 'selected_groups_label': selected_groups_label, 'can_add': context.get('can_add', True), 'can_move': context.get('can_move', True) } html = render_to_string('studio_xblock_wrapper.html', template_context) frag = wrap_fragment(frag, html) return frag
def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): """ Wraps the results of rendering an XBlock view in a div which adds a header and Studio action buttons. """ # Only add the Studio wrapper when on the container page. The "Pages" page will remain as is for now. if not context.get('is_pages_view', None) and view in PREVIEW_VIEWS: root_xblock = context.get('root_xblock') is_root = root_xblock and xblock.location == root_xblock.location is_reorderable = _is_xblock_reorderable(xblock, context) selected_groups_label = get_visibility_partition_info(xblock)['selected_groups_label'] if selected_groups_label: selected_groups_label = _('Access restricted to: {list_of_groups}').format(list_of_groups=selected_groups_label) course = modulestore().get_course(xblock.location.course_key) template_context = { 'xblock_context': context, 'xblock': xblock, 'show_preview': context.get('show_preview', True), 'content': frag.content, 'is_root': is_root, 'is_reorderable': is_reorderable, 'can_edit': context.get('can_edit', True), 'can_edit_visibility': context.get('can_edit_visibility', True), 'selected_groups_label': selected_groups_label, 'can_add': context.get('can_add', True), 'can_move': context.get('can_move', True), 'language': getattr(course, 'language', None) } html = render_to_string('studio_xblock_wrapper.html', template_context) frag = wrap_fragment(frag, html) return frag
def render(self, block, view_name, context=None): """ Render a specific view of an XBlock. """ # Users who aren't logged in are not allowed to view any views other # than public_view. They may call any handlers though. if (self.user is None or self.user.is_anonymous) and view_name != 'public_view': raise PermissionDenied # We also need to override this method because some XBlocks in the # edx-platform codebase use methods like add_webpack_to_fragment() # which create relative URLs (/static/studio/bundles/webpack-foo.js). # We want all resource URLs to be absolute, such as is done when # local_resource_url() is used. fragment = super(XBlockRuntime, self).render(block, view_name, context) needs_fix = False for resource in fragment.resources: if resource.kind == 'url' and resource.data.startswith('/'): needs_fix = True break if needs_fix: log.warning("XBlock %s returned relative resource URLs, which are deprecated", block.scope_ids.usage_id) # The Fragment API is mostly immutable, so changing a resource requires this: frag_data = fragment.to_dict() for resource in frag_data['resources']: if resource['kind'] == 'url' and resource['data'].startswith('/'): log.debug("-> Relative resource URL: %s", resource['data']) resource['data'] = get_xblock_app_config().get_site_root_url() + resource['data'] fragment = Fragment.from_dict(frag_data) # Apply any required transforms to the fragment. # We could move to doing this in wrap_xblock() and/or use an array of # wrapper methods like the ConfigurableFragmentWrapper mixin does. fragment = wrap_fragment(fragment, self.transform_static_paths_to_urls(block, fragment.content)) return fragment
def test_wrap_fragment(self): """ Verify that wrap_fragment adds new content. """ new_content = '<p>New Content<p>' fragment = self.create_fragment() wrapped_fragment = wrap_fragment(fragment, new_content) self.assertEqual('<p>New Content<p>', wrapped_fragment.content) self.assertEqual('body {background-color:red;}', wrapped_fragment.resources[0].data) self.assertEqual('alert("Hi!");', wrapped_fragment.resources[1].data)
def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): """ Wraps the results of rendering an XBlock view in a div which adds a header and Studio action buttons. """ # Only add the Studio wrapper when on the container page. The "Pages" page will remain as is for now. if not context.get('is_pages_view', None) and view in PREVIEW_VIEWS: root_xblock = context.get('root_xblock') is_root = root_xblock and xblock.location == root_xblock.location is_reorderable = _is_xblock_reorderable(xblock, context) selected_groups_label = get_visibility_partition_info( xblock)['selected_groups_label'] if selected_groups_label: selected_groups_label = _('Access restricted to: {list_of_groups}').format(list_of_groups=selected_groups_label) # lint-amnesty, pylint: disable=line-too-long course = modulestore().get_course(xblock.location.course_key) template_context = { 'xblock_context': context, 'xblock': xblock, 'show_preview': context.get('show_preview', True), 'content': frag.content, 'is_root': is_root, 'is_reorderable': is_reorderable, 'can_edit': context.get('can_edit', True), 'can_edit_visibility': context.get('can_edit_visibility', xblock.scope_ids.usage_id.context_key.is_course), 'selected_groups_label': selected_groups_label, 'can_add': context.get('can_add', True), 'can_move': context.get('can_move', xblock.scope_ids.usage_id.context_key.is_course), 'language': getattr(course, 'language', None) } if isinstance(xblock, (XModule, XModuleDescriptor)): # Add the webpackified asset tags class_name = getattr(xblock.__class__, 'unmixed_class', xblock.__class__).__name__ add_webpack_to_fragment(frag, class_name) add_webpack_to_fragment(frag, "js/factories/xblock_validation") html = render_to_string('studio_xblock_wrapper.html', template_context) frag = wrap_fragment(frag, html) return frag
def replace_urls_wrapper(block, view, frag, context, replace_url_service, static_replace_only=False): # pylint: disable=unused-argument """ Replace any static/course/jump-to-id URLs in XBlock to absolute URLs """ return wrap_fragment( frag, replace_url_service.replace_urls(frag.content, static_replace_only))
def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): """ Wraps the results of rendering an XBlock view in a div which adds a header and Studio action buttons. """ # Only add the Studio wrapper when on the container page. The "Pages" page will remain as is for now. if not context.get('is_pages_view', None) and view in PREVIEW_VIEWS: root_xblock = context.get('root_xblock') is_root = root_xblock and xblock.location == root_xblock.location is_reorderable = _is_xblock_reorderable(xblock, context) selected_groups_label = get_visibility_partition_info(xblock)['selected_groups_label'] if selected_groups_label: selected_groups_label = _('Access restricted to: {list_of_groups}').format(list_of_groups=selected_groups_label) course = modulestore().get_course(xblock.location.course_key) template_context = { 'xblock_context': context, 'xblock': xblock, 'show_preview': context.get('show_preview', True), 'content': frag.content, 'is_root': is_root, 'is_reorderable': is_reorderable, 'can_edit': context.get('can_edit', True), 'can_edit_visibility': context.get('can_edit_visibility', True), 'selected_groups_label': selected_groups_label, 'can_add': context.get('can_add', True), 'can_move': context.get('can_move', True), 'language': getattr(course, 'language', None) } if isinstance(xblock, (XModule, XModuleDescriptor)): # Add the webpackified asset tags class_name = getattr(xblock.__class__, 'unmixed_class', xblock.__class__).__name__ for tag in webpack_loader.utils.get_as_tags(class_name): frag.add_resource(tag, mimetype='text/html', placement='head') for tag in webpack_loader.utils.get_as_tags("js/factories/xblock_validation"): frag.add_resource(tag, mimetype='text/html', placement='head') html = render_to_string('studio_xblock_wrapper.html', template_context) frag = wrap_fragment(frag, html) return frag
def add_inline_analytics(_user, block, _view, frag, _context): # pylint: disable=unused-argument """ Adds a fragment for in-line analytics. Fragment consists of a button and some placeholder divs. Returns the wrapped fragment if the problem has a valid question (response). See get_responses_data function for valid responses. Otherwise, returns the fragment unchanged. """ responses_data = get_responses_data(block) if responses_data: analytics_context = { 'block_content': frag.content, 'location': unicode(block.location), 'element_id': block.location.html_id().replace('-', '_'), 'answer_dist_url': reverse('get_analytics_answer_dist'), 'responses_data': responses_data, 'course_id': unicode(block.course_id), } return wrap_fragment(frag, render_to_string('inline_analytics.html', analytics_context)) return frag
def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): """ Wraps the results of rendering an XBlock view in a div which adds a header and Studio action buttons. """ # Only add the Studio wrapper when on the container page. The "Pages" page will remain as is for now. if not context.get('is_pages_view', None) and view in PREVIEW_VIEWS: root_xblock = context.get('root_xblock') is_root = root_xblock and xblock.location == root_xblock.location is_reorderable = _is_xblock_reorderable(xblock, context) template_context = { 'xblock_context': context, 'xblock': xblock, 'show_preview': context.get('show_preview', True), 'content': frag.content, 'is_root': is_root, 'is_reorderable': is_reorderable, 'can_edit': context.get('can_edit', True), 'can_edit_visibility': context.get('can_edit_visibility', True), 'can_add': context.get('can_add', True), } html = render_to_string('studio_xblock_wrapper.html', template_context) frag = wrap_fragment(frag, html) return frag
def add_inline_analytics(_user, block, _view, frag, _context): # pylint: disable=unused-argument """ Adds a fragment for in-line analytics. Fragment consists of a button and some placeholder divs. Returns the wrapped fragment if the problem has a valid question (response). See get_responses_data function for valid responses. Otherwise, returns the fragment unchanged. """ responses_data = get_responses_data(block) if responses_data: analytics_context = { 'block_content': frag.content, 'location': unicode(block.location), 'element_id': block.location.html_id().replace('-', '_'), 'answer_dist_url': reverse('get_analytics_answer_dist'), 'responses_data': responses_data, 'course_id': unicode(block.course_id), } return wrap_fragment( frag, render_to_string('inline_analytics.html', analytics_context)) return frag
def _studio_wrap_xblock(xblock, view, frag, context, display_name_only=False): """ Wraps the results of rendering an XBlock view in a div which adds a header and Studio action buttons. """ # Only add the Studio wrapper when on the container page. The "Pages" page will remain as is for now. if not context.get("is_pages_view", None) and view in PREVIEW_VIEWS: root_xblock = context.get("root_xblock") is_root = root_xblock and xblock.location == root_xblock.location is_reorderable = _is_xblock_reorderable(xblock, context) template_context = { "xblock_context": context, "xblock": xblock, "show_preview": context.get("show_preview", True), "content": frag.content, "is_root": is_root, "is_reorderable": is_reorderable, "can_edit": context.get("can_edit", True), "can_edit_visibility": context.get("can_edit_visibility", True), "can_add": context.get("can_add", True), } html = render_to_string("studio_xblock_wrapper.html", template_context) frag = wrap_fragment(frag, html) return frag