Commit e856f07b by Mushtaq Ali

Move and undo move XBlock

- TNL-6062
- TNL-6229
parent c7dc83c3
......@@ -6,7 +6,7 @@
'common/js/components/views/feedback_notification', 'coffee/src/ajax_prefix',
'jquery.cookie'],
function(domReady, $, str, Backbone, gettext, NotificationView) {
var main;
var main, sendJSON;
main = function() {
AjaxPrefix.addAjaxPrefix(jQuery, function() {
return $("meta[name='path_prefix']").attr('content');
......@@ -45,20 +45,26 @@
});
return msg.show();
});
$.postJSON = function(url, data, callback) {
sendJSON = function(url, data, callback, type) { // eslint-disable-line no-param-reassign
if ($.isFunction(data)) {
callback = data;
data = undefined;
}
return $.ajax({
url: url,
type: 'POST',
type: type,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify(data),
success: callback
});
};
$.postJSON = function(url, data, callback) {
return sendJSON(url, data, callback, 'POST');
};
$.patchJSON = function(url, data, callback) {
return sendJSON(url, data, callback, 'PATCH');
};
return domReady(function() {
if (window.onTouchBasedDevice()) {
return $('body').addClass('touch-based-device');
......
......@@ -6,14 +6,23 @@ define([
'js/views/baseview', 'js/views/modals/base_modal',
'js/models/xblock_info', 'js/views/move_xblock_list', 'js/views/move_xblock_breadcrumb',
'common/js/components/views/feedback',
'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',
'text!templates/move-xblock-modal.underscore'
],
function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlockListView, MoveXBlockBreadcrumbView,
Feedback, StringUtils, MoveXblockModalTemplate) {
Feedback, XBlockViewUtils, MoveXBlockUtils, HtmlUtils, StringUtils, MoveXblockModalTemplate) {
'use strict';
var MoveXblockModal = BaseModal.extend({
modalSRTitle: gettext('Choose a location to move your component to'),
events: _.extend({}, BaseModal.prototype.events, {
'click .action-move': 'moveXBlock'
}),
options: $.extend({}, BaseModal.prototype.options, {
modalName: 'move-xblock',
modalSize: 'lg',
......@@ -30,6 +39,7 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
BaseModal.prototype.initialize.call(this);
this.listenTo(Backbone, 'move:breadcrumbRendered', this.focusModal);
this.sourceXBlockInfo = this.options.sourceXBlockInfo;
this.sourceParentXBlockInfo = this.options.sourceParentXBlockInfo;
this.XBlockURLRoot = this.options.XBlockURLRoot;
this.XBlockAncestorInfoURL = StringUtils.interpolate(
'{urlRoot}/{usageId}?fields=ancestorInfo',
......@@ -42,12 +52,16 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
$('.breadcrumb-container').removeClass('is-hidden');
self.renderViews(courseOutlineInfo, ancestorInfo);
});
this.targetParentXBlockInfo = null;
this.movedAlertView = null;
this.moveXBlockBreadcrumbView = null;
this.moveXBlockListView = null;
},
getTitle: function() {
return StringUtils.interpolate(
gettext('Move: {display_name}'),
{display_name: this.sourceXBlockInfo.get('display_name')}
gettext('Move: {displayName}'),
{displayName: this.sourceXBlockInfo.get('display_name')}
);
},
......@@ -57,6 +71,7 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
show: function() {
BaseModal.prototype.show.apply(this, [false]);
Feedback.prototype.inFocus.apply(this, [this.options.modalWindowClass]);
},
hide: function() {
......@@ -105,6 +120,52 @@ function($, Backbone, _, gettext, BaseView, BaseModal, XBlockInfoModel, MoveXBlo
ancestorInfo: ancestorInfo
}
);
},
moveXBlock: function() {
var self = this;
XBlockViewUtils.moveXBlock(self.sourceXBlockInfo.id, self.moveXBlockListView.parent_info.parent.id)
.done(function(response) {
if (response.move_source_locator) {
// hide modal
self.hide();
// hide xblock element
$("li.studio-xblock-wrapper[data-locator='" + self.sourceXBlockInfo.id + "']").hide();
if (self.movedAlertView) {
self.movedAlertView.hide();
}
self.movedAlertView = MoveXBlockUtils.showMovedNotification(
StringUtils.interpolate(
gettext('Success! "{displayName}" has been moved.'),
{
displayName: self.sourceXBlockInfo.get('display_name')
}
),
StringUtils.interpolate(
gettext('{link_start}Take me to the new location{link_end}'),
{
link_start: HtmlUtils.HTML('<a href="/container/' + response.parent_locator + '">'),
link_end: HtmlUtils.HTML('</a>')
}
),
HtmlUtils.interpolateHtml(
HtmlUtils.HTML(
'<a class="action-undo-move" href="#" data-source-display-name="{displayName}" ' +
'data-source-locator="{sourceLocator}" ' +
'data-source-parent-locator="{sourceParentLocator}" ' +
'data-target-index="{targetIndex}">{undoMove}</a>'
),
{
displayName: self.sourceXBlockInfo.get('display_name'),
sourceLocator: self.sourceXBlockInfo.id,
sourceParentLocator: self.sourceParentXBlockInfo.id,
targetIndex: response.source_index,
undoMove: gettext('Undo move')
}
)
);
}
});
}
});
......
......@@ -194,9 +194,11 @@ define(['jquery', 'underscore', 'gettext', 'js/views/pages/base_page', 'common/j
showMoveXBlockModal: function(event) {
var xblockElement = this.findXBlockElement(event.target),
parentXBlockElement = xblockElement.parents('.studio-xblock-wrapper'),
modal = new MoveXBlockModal({
sourceXBlockInfo: XBlockUtils.findXBlockInfo(xblockElement, this.model),
XBlockURLRoot: this.getURLRoot(),
sourceParentXBlockInfo: XBlockUtils.findXBlockInfo(parentXBlockElement, this.model),
XBlockUrlRoot: this.getURLRoot(),
outlineURL: this.options.outlineURL
});
......
/**
* Provides utilities for move xblock.
*/
define(['jquery', 'underscore', 'common/js/components/views/feedback_alert', 'js/views/utils/xblock_utils',
'js/views/utils/move_xblock_utils', 'edx-ui-toolkit/js/utils/string-utils'],
function($, _, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtils) {
'use strict';
var MovedAlertView, showMovedNotification;
MovedAlertView = AlertView.Confirmation.extend({
events: _.extend({}, AlertView.Confirmation.prototype.events, {
'click .action-undo-move': 'undoMoveXBlock'
}),
options: $.extend({}, AlertView.Confirmation.prototype.options),
initialize: function() {
AlertView.prototype.initialize.apply(this, arguments);
this.movedAlertView = null;
},
undoMoveXBlock: function(event) {
var self = this,
$moveButton = $(event.target),
sourceLocator = $moveButton.data('source-locator'),
sourceDisplayName = $moveButton.data('source-display-name'),
sourceParentLocator = $moveButton.data('source-parent-locator'),
targetIndex = $moveButton.data('target-index');
XBlockViewUtils.moveXBlock(sourceLocator, sourceParentLocator, targetIndex)
.done(function(response) {
// show XBlock element
$('.studio-xblock-wrapper[data-locator="' + response.move_source_locator + '"]').show();
if (self.movedAlertView) {
self.movedAlertView.hide();
}
self.movedAlertView = showMovedNotification(
StringUtils.interpolate(
gettext('Move cancelled. "{sourceDisplayName}" has been moved back to its original ' +
'location.'),
{
sourceDisplayName: sourceDisplayName
}
)
);
});
}
});
showMovedNotification = function(title, titleHtml, messageHtml) {
var movedAlertView = new MovedAlertView({
title: title,
titleHtml: titleHtml,
messageHtml: messageHtml,
maxShown: 10000
});
movedAlertView.show();
// scroll to top
$.smoothScroll({
offset: 0,
easing: 'swing',
speed: 1000
});
return movedAlertView;
};
return {
showMovedNotification: showMovedNotification
};
});
......@@ -6,7 +6,8 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
function($, _, gettext, ViewUtils, ModuleUtils, XBlockInfo, StringUtils) {
'use strict';
var addXBlock, duplicateXBlock, deleteXBlock, createUpdateRequestData, updateXBlockField, VisibilityState,
getXBlockVisibilityClass, getXBlockListTypeClass, updateXBlockFields, getXBlockType, findXBlockInfo;
getXBlockVisibilityClass, getXBlockListTypeClass, updateXBlockFields, getXBlockType, findXBlockInfo,
moveXBlock;
/**
* Represents the possible visibility states for an xblock:
......@@ -92,6 +93,34 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
};
/**
* Moves the specified xblock in a new parent xblock.
* @param {String} sourceLocator The xblock element to be moved.
* @param {String} targetParentLocator Target parent xblock locator of the xblock to be moved,
* new moved xblock would be placed under this xblock.
* @param {String} targetIndex Intended index position of the xblock in parent xblock. If provided,
* xblock would be placed at the particular index in the parent xblock.
* @returns {jQuery promise} A promise representing the moving of the xblock.
*/
moveXBlock = function(sourceLocator, targetParentLocator, targetIndex) {
var moveOperation = $.Deferred(),
operationText = targetIndex !== undefined ? gettext('Undo moving') : gettext('Moving');
return ViewUtils.runOperationShowingMessage(operationText,
function() {
$.patchJSON(ModuleUtils.getUpdateUrl(), {
move_source_locator: sourceLocator,
parent_locator: targetParentLocator,
target_index: targetIndex
}, function(data) {
moveOperation.resolve(data);
})
.fail(function() {
moveOperation.reject();
});
return moveOperation.promise();
});
};
/**
* Deletes the specified xblock.
* @param xblockInfo The model for the xblock to be deleted.
* @param xblockType A string representing the type of the xblock to be deleted.
......@@ -267,6 +296,7 @@ define(['jquery', 'underscore', 'gettext', 'common/js/components/utils/view_util
return {
VisibilityState: VisibilityState,
addXBlock: addXBlock,
moveXBlock: moveXBlock,
duplicateXBlock: duplicateXBlock,
deleteXBlock: deleteXBlock,
updateXBlockField: updateXBlockField,
......
......@@ -21,6 +21,8 @@
options: {
title: '',
message: '',
titleHtml: '', // an optional html that comes after the title.
messageHtml: '', // an optional html that comes after the message.
intent: null, // "warning", "confirmation", "error", "announcement", "step-required", etc
type: null, // "alert", "notification", or "prompt": set by subclass
shown: true, // is this view currently being shown?
......
/**
* The MovedAlertView to show confirmation message when moving XBlocks.
*/
(function(define) {
'use strict';
define(['jquery', 'underscore', 'common/js/components/views/feedback_alert', 'js/views/utils/xblock_utils',
'js/views/utils/move_xblock_utils', 'edx-ui-toolkit/js/utils/string-utils'],
function($, _, AlertView, XBlockViewUtils, MoveXBlockUtils, StringUtils) {
var MovedAlertView = AlertView.Confirmation.extend({
events: _.extend({}, AlertView.Confirmation.prototype.events, {
'click .action-undo-move': 'undoMoveXBlock'
}),
options: $.extend({}, AlertView.Confirmation.prototype.options),
initialize: function() {
AlertView.prototype.initialize.apply(this, arguments);
this.movedAlertView = null;
},
undoMoveXBlock: function(event) {
var self = this,
$moveButton = $(event.target),
sourceLocator = $moveButton.data('source-locator'),
sourceDisplayName = $moveButton.data('source-display-name'),
sourceParentLocator = $moveButton.data('source-parent-locator'),
targetIndex = $moveButton.data('target-index');
XBlockViewUtils.moveXBlock(sourceLocator, sourceParentLocator, targetIndex)
.done(function(response) {
// show XBlock element
$('.studio-xblock-wrapper[data-locator="' + response.move_source_locator + '"]').show();
if (self.movedAlertView) {
self.movedAlertView.hide();
}
self.movedAlertView = MoveXBlockUtils.showMovedNotification(
StringUtils.interpolate(
gettext('Move cancelled. "{sourceDisplayName}" has been moved back to its original ' +
'location.'),
{
sourceDisplayName: sourceDisplayName
}
)
);
});
}
});
return MovedAlertView;
});
}).call(this, define || RequireJS.define);
......@@ -15,8 +15,9 @@
<% } %>
<div class="copy">
<h2 class="title title-3" id="<%= type %>-<%= intent %>-title"><%- title %></h2>
<h2 class="title title-3" id="<%= type %>-<%= intent %>-title"><%- title %><% if(titleHtml) { %> <%= titleHtml %> <% } %></h2>
<% if(obj.message) { %><p class="message" id="<%= type %>-<%= intent %>-description"><%- message %></p><% } %>
<% if(messageHtml) { %> <%= messageHtml %> <% } %>
</div>
<% if(obj.actions) { %>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment