This commit implements STUD-1490, allowing creation of components on the container page. It also enables the delete and duplicate buttons now that new content can be created that would benefit. Note that it also creates shared functionality for adding components, and refactors the unit page to use it too.
165 lines
6.7 KiB
JavaScript
165 lines
6.7 KiB
JavaScript
define(["jquery", "underscore", "backbone", "gettext", "js/utils/handle_iframe_binding", "js/utils/templates",
|
|
"js/views/feedback_notification", "js/views/feedback_prompt"],
|
|
function ($, _, Backbone, gettext, IframeUtils, TemplateUtils, NotificationView, PromptView) {
|
|
/*
|
|
This view is extended from backbone to provide useful functionality for all Studio views.
|
|
This functionality includes:
|
|
- automatic expand and collapse of elements with the 'ui-toggle-expansion' class specified
|
|
- additional control of rendering by overriding 'beforeRender' or 'afterRender'
|
|
|
|
Note: the default 'afterRender' function calls a utility function 'iframeBinding' which modifies
|
|
iframe src urls on a page so that they are rendered as part of the DOM.
|
|
*/
|
|
|
|
var BaseView = Backbone.View.extend({
|
|
events: {
|
|
"click .ui-toggle-expansion": "toggleExpandCollapse"
|
|
},
|
|
|
|
//override the constructor function
|
|
constructor: function(options) {
|
|
_.bindAll(this, 'beforeRender', 'render', 'afterRender');
|
|
var _this = this;
|
|
this.render = _.wrap(this.render, function (render, options) {
|
|
_this.beforeRender();
|
|
render(options);
|
|
_this.afterRender();
|
|
return _this;
|
|
});
|
|
|
|
//call Backbone's own constructor
|
|
Backbone.View.prototype.constructor.apply(this, arguments);
|
|
},
|
|
|
|
beforeRender: function() {
|
|
},
|
|
|
|
render: function() {
|
|
return this;
|
|
},
|
|
|
|
afterRender: function() {
|
|
IframeUtils.iframeBinding(this);
|
|
},
|
|
|
|
toggleExpandCollapse: function(event) {
|
|
var target = $(event.target);
|
|
// Don't propagate the event as it is possible that two views will both contain
|
|
// this element, e.g. clicking on the element of a child view container in a parent.
|
|
event.stopPropagation();
|
|
event.preventDefault();
|
|
target.closest('.expand-collapse').toggleClass('expand').toggleClass('collapse');
|
|
target.closest('.is-collapsible, .window').toggleClass('collapsed');
|
|
target.closest('.is-collapsible').children('article').slideToggle();
|
|
},
|
|
|
|
showLoadingIndicator: function() {
|
|
$('.ui-loading').show();
|
|
},
|
|
|
|
hideLoadingIndicator: function() {
|
|
$('.ui-loading').hide();
|
|
},
|
|
|
|
/**
|
|
* Confirms with the user whether to run an operation or not, and then runs it if desired.
|
|
*/
|
|
confirmThenRunOperation: function(title, message, actionLabel, operation) {
|
|
var self = this;
|
|
return new PromptView.Warning({
|
|
title: title,
|
|
message: message,
|
|
actions: {
|
|
primary: {
|
|
text: actionLabel,
|
|
click: function(prompt) {
|
|
prompt.hide();
|
|
operation();
|
|
}
|
|
},
|
|
secondary: {
|
|
text: gettext('Cancel'),
|
|
click: function(prompt) {
|
|
return prompt.hide();
|
|
}
|
|
}
|
|
}
|
|
}).show();
|
|
},
|
|
|
|
/**
|
|
* Shows a progress message for the duration of an asynchronous operation.
|
|
* Note: this does not remove the notification upon failure because an error
|
|
* will be shown that shouldn't be removed.
|
|
* @param message The message to show.
|
|
* @param operation A function that returns a promise representing the operation.
|
|
*/
|
|
runOperationShowingMessage: function(message, operation) {
|
|
var notificationView;
|
|
notificationView = new NotificationView.Mini({
|
|
title: gettext(message)
|
|
});
|
|
notificationView.show();
|
|
return operation().done(function() {
|
|
notificationView.hide();
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Disables a given element when a given operation is running.
|
|
* @param {jQuery} element: the element to be disabled.
|
|
* @param operation: the operation during whose duration the
|
|
* element should be disabled. The operation should return
|
|
* a JQuery promise.
|
|
*/
|
|
disableElementWhileRunning: function(element, operation) {
|
|
element.addClass("is-disabled");
|
|
return operation().always(function() {
|
|
element.removeClass("is-disabled");
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Loads the named template from the page, or logs an error if it fails.
|
|
* @param name The name of the template.
|
|
* @returns The loaded template.
|
|
*/
|
|
loadTemplate: function(name) {
|
|
return TemplateUtils.loadTemplate(name);
|
|
},
|
|
|
|
/**
|
|
* Returns the relative position that the element is scrolled from the top of the view port.
|
|
* @param element The element in question.
|
|
*/
|
|
getScrollOffset: function(element) {
|
|
var elementTop = element.offset().top;
|
|
return elementTop - $(window).scrollTop();
|
|
},
|
|
|
|
/**
|
|
* Scrolls the window so that the element is scrolled down to the specified relative position
|
|
* from the top of the view port.
|
|
* @param element The element in question.
|
|
* @param offset The amount by which the element should be scrolled from the top of the view port.
|
|
*/
|
|
setScrollOffset: function(element, offset) {
|
|
var elementTop = element.offset().top,
|
|
newScrollTop = elementTop - offset;
|
|
this.setScrollTop(newScrollTop);
|
|
},
|
|
|
|
/**
|
|
* Performs an animated scroll so that the window has the specified scroll top.
|
|
* @param scrollTop The desired scroll top for the window.
|
|
*/
|
|
setScrollTop: function(scrollTop) {
|
|
$('html, body').animate({
|
|
scrollTop: scrollTop
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
return BaseView;
|
|
});
|