Add new container page that can display nested xblocks
This is the changes for STUD-1244, which introduces the ability for Studio to display arbitrarily nested xblocks. In this change, a new container page is introduced which can display nested xblocks. In particular, the xblock type of 'vertical' is special cased to be shown inline as a collapsible section. The unit page is mostly unchanged, except that container xblock's are shown as a link to their container page, rather than being shown inline.
This commit is contained in:
@@ -1,50 +1,80 @@
|
||||
define(
|
||||
[
|
||||
"jquery", "underscore",
|
||||
"js/views/baseview",
|
||||
"js/utils/handle_iframe_binding",
|
||||
"sinon"
|
||||
],
|
||||
function ($, _, BaseView, IframeBinding, sinon) {
|
||||
define(["jquery", "underscore", "js/views/baseview", "js/utils/handle_iframe_binding", "sinon"],
|
||||
function ($, _, BaseView, IframeBinding, sinon) {
|
||||
|
||||
describe("BaseView check", function () {
|
||||
var baseView;
|
||||
var iframeBinding_spy;
|
||||
describe("BaseView", function() {
|
||||
var baseViewPrototype;
|
||||
|
||||
beforeEach(function () {
|
||||
iframeBinding_spy = sinon.spy(IframeBinding, "iframeBinding");
|
||||
baseView = BaseView.prototype;
|
||||
describe("BaseView rendering", function () {
|
||||
var iframeBinding_spy;
|
||||
|
||||
spyOn(baseView, 'initialize');
|
||||
spyOn(baseView, 'beforeRender');
|
||||
spyOn(baseView, 'render');
|
||||
spyOn(baseView, 'afterRender').andCallThrough();
|
||||
});
|
||||
beforeEach(function () {
|
||||
baseViewPrototype = BaseView.prototype;
|
||||
iframeBinding_spy = sinon.spy(IframeBinding, "iframeBinding");
|
||||
|
||||
afterEach(function () {
|
||||
iframeBinding_spy.restore();
|
||||
});
|
||||
spyOn(baseViewPrototype, 'initialize');
|
||||
spyOn(baseViewPrototype, 'beforeRender');
|
||||
spyOn(baseViewPrototype, 'render').andCallThrough();
|
||||
spyOn(baseViewPrototype, 'afterRender').andCallThrough();
|
||||
});
|
||||
|
||||
it('calls before and after render functions when render of baseview is called', function () {
|
||||
var baseview_temp = new BaseView()
|
||||
baseview_temp.render();
|
||||
afterEach(function () {
|
||||
iframeBinding_spy.restore();
|
||||
});
|
||||
|
||||
expect(baseView.initialize).toHaveBeenCalled();
|
||||
expect(baseView.beforeRender).toHaveBeenCalled();
|
||||
expect(baseView.render).toHaveBeenCalled();
|
||||
expect(baseView.afterRender).toHaveBeenCalled();
|
||||
});
|
||||
it('calls before and after render functions when render of baseview is called', function () {
|
||||
var baseView = new BaseView();
|
||||
baseView.render();
|
||||
|
||||
it('calls iframeBinding function when afterRender of baseview is called', function () {
|
||||
var baseview_temp = new BaseView()
|
||||
baseview_temp.render();
|
||||
expect(baseView.afterRender).toHaveBeenCalled();
|
||||
expect(iframeBinding_spy.called).toEqual(true);
|
||||
expect(baseViewPrototype.initialize).toHaveBeenCalled();
|
||||
expect(baseViewPrototype.beforeRender).toHaveBeenCalled();
|
||||
expect(baseViewPrototype.render).toHaveBeenCalled();
|
||||
expect(baseViewPrototype.afterRender).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
//check calls count of iframeBinding function
|
||||
expect(iframeBinding_spy.callCount).toBe(1);
|
||||
IframeBinding.iframeBinding();
|
||||
expect(iframeBinding_spy.callCount).toBe(2);
|
||||
it('calls iframeBinding function when afterRender of baseview is called', function () {
|
||||
var baseView = new BaseView();
|
||||
baseView.render();
|
||||
expect(baseViewPrototype.afterRender).toHaveBeenCalled();
|
||||
expect(iframeBinding_spy.called).toEqual(true);
|
||||
|
||||
//check calls count of iframeBinding function
|
||||
expect(iframeBinding_spy.callCount).toBe(1);
|
||||
IframeBinding.iframeBinding();
|
||||
expect(iframeBinding_spy.callCount).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Expand/Collapse", function () {
|
||||
var view, MockCollapsibleViewClass;
|
||||
|
||||
MockCollapsibleViewClass = BaseView.extend({
|
||||
initialize: function() {
|
||||
this.viewHtml = readFixtures('mock/mock-collapsible-view.underscore');
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html(this.viewHtml);
|
||||
}
|
||||
});
|
||||
|
||||
it('hides a collapsible node when clicking on the toggle link', function () {
|
||||
view = new MockCollapsibleViewClass();
|
||||
view.render();
|
||||
view.$('.ui-toggle-expansion').click();
|
||||
expect(view.$('.expand-collapse')).toHaveClass('expand');
|
||||
expect(view.$('.expand-collapse')).not.toHaveClass('collapse');
|
||||
expect(view.$('.is-collapsible')).toHaveClass('collapsed');
|
||||
});
|
||||
|
||||
it('expands a collapsible node when clicking twice on the toggle link', function () {
|
||||
view = new MockCollapsibleViewClass();
|
||||
view.render();
|
||||
view.$('.ui-toggle-expansion').click();
|
||||
view.$('.ui-toggle-expansion').click();
|
||||
expect(view.$('.expand-collapse')).toHaveClass('collapse');
|
||||
expect(view.$('.expand-collapse')).not.toHaveClass('expand');
|
||||
expect(view.$('.is-collapsible')).not.toHaveClass('collapsed');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
92
cms/static/js/spec/views/xblock_spec.js
Normal file
92
cms/static/js/spec/views/xblock_spec.js
Normal file
@@ -0,0 +1,92 @@
|
||||
define([ "jquery", "js/spec/create_sinon", "URI", "js/views/xblock", "js/models/xblock_info",
|
||||
"xmodule", "coffee/src/main", "xblock/cms.runtime.v1"],
|
||||
function ($, create_sinon, URI, XBlockView, XBlockInfo) {
|
||||
|
||||
describe("XBlockView", function() {
|
||||
var model, xblockView, mockXBlockHtml, respondWithMockXBlockFragment;
|
||||
|
||||
beforeEach(function () {
|
||||
model = new XBlockInfo({
|
||||
id: 'testCourse/branch/published/block/verticalFFF',
|
||||
display_name: 'Test Unit',
|
||||
category: 'vertical'
|
||||
});
|
||||
xblockView = new XBlockView({
|
||||
model: model
|
||||
});
|
||||
});
|
||||
|
||||
mockXBlockHtml = readFixtures('mock/mock-xblock.underscore');
|
||||
|
||||
respondWithMockXBlockFragment = function(requests, response) {
|
||||
var requestIndex = requests.length - 1;
|
||||
create_sinon.respondWithJson(requests, response, requestIndex);
|
||||
};
|
||||
|
||||
it('can render a nested xblock', function() {
|
||||
var requests = create_sinon.requests(this);
|
||||
xblockView.render();
|
||||
respondWithMockXBlockFragment(requests, {
|
||||
html: mockXBlockHtml,
|
||||
"resources": []
|
||||
});
|
||||
|
||||
expect(xblockView.$el.select('.xblock-header')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe("XBlock rendering", function() {
|
||||
var postXBlockRequest;
|
||||
|
||||
postXBlockRequest = function(requests, resources) {
|
||||
$.ajax({
|
||||
url: "test_url",
|
||||
type: 'GET',
|
||||
success: function(fragment) {
|
||||
xblockView.renderXBlockFragment(fragment, this.$el);
|
||||
}
|
||||
});
|
||||
respondWithMockXBlockFragment(requests, {
|
||||
html: mockXBlockHtml,
|
||||
resources: resources
|
||||
});
|
||||
expect(xblockView.$el.select('.xblock-header')).toBeTruthy();
|
||||
};
|
||||
|
||||
it('can render an xblock with no CSS or JavaScript', function() {
|
||||
var requests = create_sinon.requests(this);
|
||||
postXBlockRequest(requests, []);
|
||||
});
|
||||
|
||||
it('can render an xblock with required CSS', function() {
|
||||
var requests = create_sinon.requests(this),
|
||||
mockCssText = "// Just a comment",
|
||||
mockCssUrl = "mock.css",
|
||||
headHtml;
|
||||
postXBlockRequest(requests, [
|
||||
["hash1", { mimetype: "text/css", kind: "text", data: mockCssText }],
|
||||
["hash2", { mimetype: "text/css", kind: "url", data: mockCssUrl }]
|
||||
]);
|
||||
headHtml = $('head').html();
|
||||
expect(headHtml).toContain(mockCssText);
|
||||
expect(headHtml).toContain(mockCssUrl);
|
||||
});
|
||||
|
||||
it('can render an xblock with required JavaScript', function() {
|
||||
var requests = create_sinon.requests(this);
|
||||
postXBlockRequest(requests, [
|
||||
["hash3", { mimetype: "application/javascript", kind: "text", data: "window.test = 100;" }]
|
||||
]);
|
||||
expect(window.test).toBe(100);
|
||||
});
|
||||
|
||||
it('can render an xblock with required HTML', function() {
|
||||
var requests = create_sinon.requests(this),
|
||||
mockHeadTag = "<title>Test Title</title>";
|
||||
postXBlockRequest(requests, [
|
||||
["hash4", { mimetype: "text/html", placement: "head", data: mockHeadTag }]
|
||||
]);
|
||||
expect($('head').html()).toContain(mockHeadTag);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user