Files
edx-platform/cms/static/js/views/modals/move_xblock_modal.js
muhammad-ammar 090ce1d0e5 move dialog fix
EDUCATOR-292
2017-06-12 16:08:55 +05:00

193 lines
7.7 KiB
JavaScript

/**
* The MoveXblockModal to move XBlocks in course.
*/
define([
'jquery',
'backbone',
'underscore',
'gettext',
'js/views/baseview',
'js/views/utils/xblock_utils',
'js/views/utils/move_xblock_utils',
'edx-ui-toolkit/js/utils/html-utils',
'edx-ui-toolkit/js/utils/string-utils',
'common/js/components/views/feedback',
'js/models/xblock_info',
'js/views/modals/base_modal',
'js/views/move_xblock_list',
'js/views/move_xblock_breadcrumb',
'text!templates/move-xblock-modal.underscore'
],
function($, Backbone, _, gettext, BaseView, XBlockViewUtils, MoveXBlockUtils, HtmlUtils, StringUtils, Feedback,
XBlockInfoModel, BaseModal, MoveXBlockListView, MoveXBlockBreadcrumbView, MoveXblockModalTemplate) {
'use strict';
var MoveXblockModal = BaseModal.extend({
events: _.extend({}, BaseModal.prototype.events, {
'click .action-move:not(.is-disabled)': 'moveXBlock'
}),
options: $.extend({}, BaseModal.prototype.options, {
modalName: 'move-xblock',
modalSize: 'lg',
showEditorModeButtons: false,
addPrimaryActionButton: true,
primaryActionButtonType: 'move',
viewSpecificClasses: 'move-modal',
primaryActionButtonTitle: gettext('Move'),
modalSRTitle: gettext('Choose a location to move your component to')
}),
initialize: function() {
var self = this;
BaseModal.prototype.initialize.call(this);
this.sourceXBlockInfo = this.options.sourceXBlockInfo;
this.sourceParentXBlockInfo = this.options.sourceParentXBlockInfo;
this.targetParentXBlockInfo = null;
this.XBlockURLRoot = this.options.XBlockURLRoot;
this.XBlockAncestorInfoURL = StringUtils.interpolate(
'{urlRoot}/{usageId}?fields=ancestorInfo',
{urlRoot: this.XBlockURLRoot, usageId: this.sourceXBlockInfo.get('id')}
);
this.outlineURL = this.options.outlineURL;
this.options.title = this.getTitle();
this.fetchCourseOutline().done(function(courseOutlineInfo, ancestorInfo) {
$('.ui-loading').addClass('is-hidden');
$('.breadcrumb-container').removeClass('is-hidden');
self.renderViews(courseOutlineInfo, ancestorInfo);
});
this.listenTo(Backbone, 'move:breadcrumbRendered', this.focusModal);
this.listenTo(Backbone, 'move:enableMoveOperation', this.enableMoveOperation);
this.listenTo(Backbone, 'move:hideMoveModal', this.hide);
},
getTitle: function() {
return StringUtils.interpolate(
gettext('Move: {displayName}'),
{displayName: this.sourceXBlockInfo.get('display_name')}
);
},
getContentHtml: function() {
return _.template(MoveXblockModalTemplate)({});
},
show: function() {
BaseModal.prototype.show.apply(this, [false]);
this.updateMoveState(false);
MoveXBlockUtils.hideMovedNotification();
},
hide: function() {
if (this.moveXBlockListView) {
this.moveXBlockListView.remove();
}
if (this.moveXBlockBreadcrumbView) {
this.moveXBlockBreadcrumbView.remove();
}
BaseModal.prototype.hide.apply(this);
Feedback.prototype.outFocus.apply(this);
},
resize: function() {
// Do Nothing. Overridden to use our own styling instead of one provided by base modal
},
focusModal: function() {
Feedback.prototype.inFocus.apply(this, [this.options.modalWindowClass]);
$(this.options.modalWindowClass).focus();
},
fetchCourseOutline: function() {
return $.when(
this.fetchData(this.outlineURL),
this.fetchData(this.XBlockAncestorInfoURL)
);
},
fetchData: function(url) {
var deferred = $.Deferred();
$.ajax({
url: url,
contentType: 'application/json',
dataType: 'json',
type: 'GET'
}).done(function(data) {
deferred.resolve(data);
}).fail(function() {
deferred.reject();
});
return deferred.promise();
},
renderViews: function(courseOutlineInfo, ancestorInfo) {
this.moveXBlockBreadcrumbView = new MoveXBlockBreadcrumbView({});
this.moveXBlockListView = new MoveXBlockListView(
{
model: new XBlockInfoModel(courseOutlineInfo, {parse: true}),
sourceXBlockInfo: this.sourceXBlockInfo,
ancestorInfo: ancestorInfo
}
);
},
updateMoveState: function(isValidMove) {
var $moveButton = this.$el.find('.action-move');
if (isValidMove) {
$moveButton.removeClass('is-disabled');
} else {
$moveButton.addClass('is-disabled');
}
},
isValidCategory: function(targetParentXBlockInfo) {
var basicBlockTypes = ['course', 'chapter', 'sequential', 'vertical'],
sourceParentType = this.sourceParentXBlockInfo.get('category'),
targetParentType = targetParentXBlockInfo.get('category'),
sourceParentHasChildren = this.sourceParentXBlockInfo.get('has_children'),
targetParentHasChildren = targetParentXBlockInfo.get('has_children');
// Treat source parent component as vertical to support move child components under content experiment
// and other similar xblocks.
if (sourceParentHasChildren && !_.contains(basicBlockTypes, sourceParentType)) {
sourceParentType = 'vertical'; // eslint-disable-line no-param-reassign
}
// Treat target parent component as a vertical to support move to parentable target parent components.
// Also, moving a component directly to content experiment is not allowed, we need to visit to group level.
if (targetParentHasChildren && !_.contains(basicBlockTypes, targetParentType) &&
targetParentType !== 'split_test') {
targetParentType = 'vertical'; // eslint-disable-line no-param-reassign
}
return targetParentType === sourceParentType;
},
enableMoveOperation: function(targetParentXBlockInfo) {
var isValidMove = false;
// update target parent on navigation
this.targetParentXBlockInfo = targetParentXBlockInfo;
if (this.isValidCategory(targetParentXBlockInfo) &&
this.sourceParentXBlockInfo.id !== targetParentXBlockInfo.id && // same parent case
this.sourceXBlockInfo.id !== targetParentXBlockInfo.id) { // same source item case
isValidMove = true;
}
this.updateMoveState(isValidMove);
},
moveXBlock: function() {
MoveXBlockUtils.moveXBlock(
{
sourceXBlockElement: $("li.studio-xblock-wrapper[data-locator='" + this.sourceXBlockInfo.id + "']"),
sourceDisplayName: this.sourceXBlockInfo.get('display_name'),
sourceLocator: this.sourceXBlockInfo.id,
sourceParentLocator: this.sourceParentXBlockInfo.id,
targetParentLocator: this.targetParentXBlockInfo.id
}
);
}
});
return MoveXblockModal;
});