diff --git a/cms/djangoapps/contentstore/views/block.py b/cms/djangoapps/contentstore/views/block.py index d52cc5eecfd4..46e49c2fae4a 100644 --- a/cms/djangoapps/contentstore/views/block.py +++ b/cms/djangoapps/contentstore/views/block.py @@ -9,12 +9,13 @@ from django.db import transaction from django.http import Http404, HttpResponse from django.utils.translation import gettext as _ +from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.http import require_http_methods from opaque_keys.edx.keys import CourseKey from web_fragments.fragment import Fragment from cms.lib.xblock.authoring_mixin import VISIBILITY_VIEW -from common.djangoapps.edxmako.shortcuts import render_to_string +from common.djangoapps.edxmako.shortcuts import render_to_response, render_to_string from common.djangoapps.student.auth import ( has_studio_read_access, has_studio_write_access, @@ -38,10 +39,11 @@ STUDIO_VIEW, ) # lint-amnesty, pylint: disable=wrong-import-order - from ..helpers import ( is_unit, ) +from ..utils import get_container_handler_context +from .component import _get_item_in_course from .preview import get_preview_fragment from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import ( @@ -300,6 +302,30 @@ def xblock_view_handler(request, usage_key_string, view_name): return HttpResponse(status=406) +@xframe_options_exempt +@require_http_methods("GET") +@login_required +def xblock_actions_view(request, usage_key_string, action_name): + """ + Return rendered xblock action view. + The action name should be provided as an argument. + Valid options for action names are edit and move. + """ + usage_key = usage_key_with_run(usage_key_string) + if not has_studio_read_access(request.user, usage_key.course_key): + raise PermissionDenied() + if action_name not in ['edit', 'move']: + return HttpResponse(status=404) + + store = modulestore() + + with store.bulk_operations(usage_key.course_key): + course, xblock, lms_link, preview_lms_link = _get_item_in_course(request, usage_key) + container_handler_context = get_container_handler_context(request, usage_key, course, xblock) + container_handler_context.update({'action_name': action_name}) + return render_to_response('container_editor.html', container_handler_context) + + @require_http_methods("GET") @login_required @expect_json diff --git a/cms/static/js/views/modals/base_modal.js b/cms/static/js/views/modals/base_modal.js index 65b7f06ae021..828289533a73 100644 --- a/cms/static/js/views/modals/base_modal.js +++ b/cms/static/js/views/modals/base_modal.js @@ -119,6 +119,10 @@ define(['jquery', 'underscore', 'gettext', 'js/views/baseview'], event.preventDefault(); event.stopPropagation(); // Make sure parent modals don't see the click } + window.parent.postMessage({ + method: 'close_modal', + msg: 'Sends a message when the modal window is closed' + }, '*'); this.hide(); }, diff --git a/cms/static/js/views/modals/edit_xblock.js b/cms/static/js/views/modals/edit_xblock.js index 7182d8b0e51a..0ced05cea737 100644 --- a/cms/static/js/views/modals/edit_xblock.js +++ b/cms/static/js/views/modals/edit_xblock.js @@ -208,6 +208,11 @@ function($, _, Backbone, gettext, BaseModal, ViewUtils, XBlockViewUtils, XBlockE // Notify child views to stop listening events Backbone.trigger('xblock:editorModalHidden'); + window.parent.postMessage({ + method: 'close_modal', + msg: 'Sends a message when the edit modal window is closed' + }, '*'); + BaseModal.prototype.hide.call(this); // Notify the runtime that the modal has been hidden diff --git a/cms/static/js/views/utils/move_xblock_utils.js b/cms/static/js/views/utils/move_xblock_utils.js index 9bde9c6d087e..f3bcc675f1da 100644 --- a/cms/static/js/views/utils/move_xblock_utils.js +++ b/cms/static/js/views/utils/move_xblock_utils.js @@ -26,8 +26,25 @@ function($, _, Backbone, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, .done(function(response) { // hide modal Backbone.trigger('move:hideMoveModal'); - // hide xblock element - data.sourceXBlockElement.hide(); + if (data.sourceXBlockElement) { + // hide xblock element + data.sourceXBlockElement.hide(); + } + + window.parent.postMessage({ + method: 'move_xblock', + msg: 'Sends a message when the xblock is moved', + params: { + sourceDisplayName: data.sourceDisplayName, + sourceLocator: data.sourceLocator, + targetParentLocator: data.targetParentLocator, + } + }, '*'); + window.parent.postMessage({ + method: 'close_modal', + msg: 'Sends a message when the modal window is closed' + }, '*'); + showMovedNotification( StringUtils.interpolate( gettext('Success! "{displayName}" has been moved.'), @@ -36,7 +53,7 @@ function($, _, Backbone, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, } ), { - sourceXBlockElement: data.sourceXBlockElement, + sourceXBlockElement: data.sourceXBlockElement ? data.sourceXBlockElement : null, sourceDisplayName: data.sourceDisplayName, sourceLocator: data.sourceLocator, sourceParentLocator: data.sourceParentLocator, @@ -78,7 +95,7 @@ function($, _, Backbone, Feedback, AlertView, XBlockViewUtils, MoveXBlockUtils, click: function() { undoMoveXBlock( { - sourceXBlockElement: data.sourceXBlockElement, + sourceXBlockElement: data.sourceXBlockElement ? data.sourceXBlockElement : null, sourceDisplayName: data.sourceDisplayName, sourceLocator: data.sourceLocator, sourceParentLocator: data.sourceParentLocator, diff --git a/cms/templates/container_editor.html b/cms/templates/container_editor.html new file mode 100644 index 000000000000..43f23d2100a4 --- /dev/null +++ b/cms/templates/container_editor.html @@ -0,0 +1,223 @@ +## coding=utf-8 +## mako + +## Pages currently use v1 styling by default. Once the Pattern Library +## rollout has been completed, this default can be switched to v2. +<%! main_css = "style-main-v1" %> + +## Standard imports +<%namespace name='static' file='static_content.html'/> +<%! +from django.utils.translation import gettext as _ +from cms.djangoapps.contentstore.config.waffle import CUSTOM_RELATIVE_DATES +from lms.djangoapps.branding import api as branding_api +from openedx.core.djangoapps.util.user_messages import PageLevelMessages +from openedx.core.djangolib.js_utils import ( + dump_js_escaped_json, js_escaped_string +) +from openedx.core.djangolib.markup import HTML +from openedx.core.release import RELEASE_LINE +%> +<%def name="online_help_token()"> +<% + return "container" +%> +%def> +<%! +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 openedx.core.djangolib.js_utils import ( + dump_js_escaped_json, js_escaped_string +) +from openedx.core.djangolib.markup import HTML, Text +%> + +<%page expression_filter="h"/> + + + +
+ + + +