Files
edx-platform/cms/static/js/views/container.js
2014-06-20 11:41:23 -04:00

124 lines
5.3 KiB
JavaScript

define(["jquery", "underscore", "js/views/xblock", "js/utils/module", "gettext", "js/views/feedback_notification",
"jquery.ui"], // The container view uses sortable, which is provided by jquery.ui.
function ($, _, XBlockView, ModuleUtils, gettext, NotificationView) {
var reorderableClass = '.reorderable-container',
sortableInitializedClass = '.ui-sortable',
studioXBlockWrapperClass = '.studio-xblock-wrapper';
var ContainerView = XBlockView.extend({
xblockReady: function () {
XBlockView.prototype.xblockReady.call(this);
var reorderableContainer = this.$(reorderableClass),
alreadySortable = this.$(sortableInitializedClass),
newParent,
oldParent,
self = this;
alreadySortable.sortable("destroy");
reorderableContainer.sortable({
handle: '.drag-handle',
stop: function (event, ui) {
var saving, hideSaving, removeFromParent;
if (_.isUndefined(oldParent)) {
// If no actual change occurred,
// oldParent will never have been set.
return;
}
saving = new NotificationView.Mini({
title: gettext('Saving…')
});
saving.show();
hideSaving = function () {
saving.hide();
};
// If moving from one container to another,
// add to new container before deleting from old to
// avoid creating an orphan if the addition fails.
if (newParent) {
removeFromParent = oldParent;
self.updateChildren(newParent, function () {
self.updateChildren(removeFromParent, hideSaving);
});
} else {
// No new parent, only reordering within same container.
self.updateChildren(oldParent, hideSaving);
}
oldParent = undefined;
newParent = undefined;
},
update: function (event, ui) {
// When dragging from one ol to another, this method
// will be called twice (once for each list). ui.sender will
// be null if the change is related to the list the element
// was originally in (the case of a move within the same container
// or the deletion from a container when moving to a new container).
var parent = $(event.target).closest(studioXBlockWrapperClass);
if (ui.sender) {
// Move to a new container (the addition part).
newParent = parent;
} else {
// Reorder inside a container, or deletion when moving to new container.
oldParent = parent;
}
},
helper: "original",
opacity: '0.5',
placeholder: 'component-placeholder',
forcePlaceholderSize: true,
axis: 'y',
items: '> .is-draggable',
connectWith: reorderableClass,
tolerance: "pointer"
});
},
updateChildren: function (targetParent, successCallback) {
var children, childLocators;
// Find descendants with class "studio-xblock-wrapper" whose parent === targetParent.
// This is necessary to filter our grandchildren, great-grandchildren, etc.
children = targetParent.find(studioXBlockWrapperClass).filter(function () {
var parent = $(this).parent().closest(studioXBlockWrapperClass);
return parent.data('locator') === targetParent.data('locator');
});
childLocators = _.map(
children,
function (child) {
return $(child).data('locator');
}
);
$.ajax({
url: ModuleUtils.getUpdateUrl(targetParent.data('locator')),
type: 'PUT',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({
children: childLocators
}),
success: function () {
// change data-parent on the element moved.
if (successCallback) {
successCallback();
}
}
});
},
refresh: function() {
this.$(sortableInitializedClass).sortable('refresh');
}
});
return ContainerView;
}); // end define();