Entrance Exam authoring and messaging updates

Multi-commit history:
- hide drag functionality for entrance exam section.
- hide entrance exam subsection elements e.g. delete, drag, name etc.
- show unit/verticals expanded in case of entrance exam
- modify code in order to allow user to update entrance exam score from UI.
- write down unit tests.
- write down Jasmine tests.
- add bok-choy test
- updated bok-choy test
- internationalize string
- repositioned sequential block creatori
- SOL-221 (entrance exam message)
- SOL-199 LMS Part (show entrance exam content) and hide the course navigation bar.
- redirect the view in case of entrance exam.
- update code structure as per suggestions
- write down unit tests
- fix pep8
- instead of hiding the exam requirement message, now also showing the exam the completion message (success state).
- write down unit test to show exam completion message.
- Update code as per review suggestions
- update doc string
- addressed review suggestions
- change sequential message text
- css adjustments
- added new css class for entrance exam score in studio
- added Jasmine test for remaning coverage
- sequential message should appear under the context of entrance exam subsection.
- updated text in CMS and LMS as per suggestions.
- added unit text to insure sequential message should not be present in other chapters rather then entrance exam.
- skip setter if empty prerequisite course list
- exclude logic from xblock_info.js that is specifically related to entrance exam.
- added js tests and updated code as per suggestions
- added tests
- addressed several PR issues
- Several small fixes (style, refactoring)
- Fixed score update issue
- added some more unit tests.
- code suggested changes.
- addressed PR feedback
This commit is contained in:
asadiqbal
2015-01-29 18:18:38 +05:00
committed by Matt Drayer
parent 57c38649ba
commit 5a7ac441e5
19 changed files with 669 additions and 102 deletions

View File

@@ -133,9 +133,19 @@ function(Backbone, _, str, ModuleUtils) {
*/
'has_content_group_components': null,
/**
* Indicate the type of xblock
* actions defines the state of delete, drag and child add functionality for a xblock.
* currently, each xblock has default value of 'True' for keys: deletable, draggable and childAddable.
*/
'override_type': null
'actions': null,
/**
* Header visible to UI.
*/
'is_header_visible': null,
/**
* Optional explanatory message about the xblock.
*/
'explanatory_message': null
},
initialize: function () {
@@ -172,13 +182,33 @@ function(Backbone, _, str, ModuleUtils) {
return !this.get('published') || this.get('has_changes');
},
canBeDeleted: function(){
//get the type of xblock
if(this.get('override_type') != null) {
var type = this.get('override_type');
isDeletable: function() {
return this.isActionRequired('deletable');
},
//hide/remove the delete trash icon if type is entrance exam.
if (_.has(type, 'is_entrance_exam') && type['is_entrance_exam']) {
isDraggable: function() {
return this.isActionRequired('draggable');
},
isChildAddable: function(){
return this.isActionRequired('childAddable');
},
isHeaderVisible: function(){
if(this.get('is_header_visible') !== null) {
return this.get('is_header_visible');
}
return true;
},
/**
* Return true if action is required e.g. delete, drag, add new child etc or if given key is not present.
* @return {boolean}
*/
isActionRequired: function(actionName) {
var actions = this.get('actions');
if(actions !== null) {
if (_.has(actions, actionName) && !actions[actionName]) {
return false;
}
}
@@ -188,8 +218,8 @@ function(Backbone, _, str, ModuleUtils) {
/**
* Return a list of convenience methods to check affiliation to the category.
* @return {Array}
*/
getCategoryHelpers: function () {
*/
getCategoryHelpers: function () {
var categories = ['course', 'chapter', 'sequential', 'vertical'],
helpers = {};
@@ -200,15 +230,15 @@ function(Backbone, _, str, ModuleUtils) {
}, this);
return helpers;
},
},
/**
* Check if we can edit current XBlock or not on Course Outline page.
* @return {Boolean}
*/
isEditableOnCourseOutline: function() {
return this.isSequential() || this.isChapter() || this.isVertical();
}
/**
* Check if we can edit current XBlock or not on Course Outline page.
* @return {Boolean}
*/
isEditableOnCourseOutline: function() {
return this.isSequential() || this.isChapter() || this.isVertical();
}
});
return XBlockInfo;
});

View File

@@ -7,16 +7,47 @@ define(['backbone', 'js/models/xblock_info'],
expect(new XBlockInfo({'category': 'sequential'}).isEditableOnCourseOutline()).toBe(true);
expect(new XBlockInfo({'category': 'vertical'}).isEditableOnCourseOutline()).toBe(true);
});
});
it('cannot delete an entrance exam', function(){
expect(new XBlockInfo({'category': 'chapter', 'override_type': {'is_entrance_exam':true}})
.canBeDeleted()).toBe(false);
describe('XblockInfo actions state and header visibility ', function() {
it('works correct to hide icons e.g. trash icon, drag when actions are not required', function(){
expect(new XBlockInfo({'category': 'chapter', 'actions': {'deletable':false}})
.isDeletable()).toBe(false);
expect(new XBlockInfo({'category': 'chapter', 'actions': {'draggable':false}})
.isDraggable()).toBe(false);
expect(new XBlockInfo({'category': 'chapter', 'actions': {'childAddable':false}})
.isChildAddable()).toBe(false);
});
it('can delete module rather then entrance exam', function(){
expect(new XBlockInfo({'category': 'chapter', 'override_type': {'is_entrance_exam':false}}).canBeDeleted()).toBe(true);
expect(new XBlockInfo({'category': 'chapter', 'override_type': {}}).canBeDeleted()).toBe(true);
it('works correct to show icons e.g. trash icon, drag when actions are required', function(){
expect(new XBlockInfo({'category': 'chapter', 'actions': {'deletable':true}})
.isDeletable()).toBe(true);
expect(new XBlockInfo({'category': 'chapter', 'actions': {'draggable':true}})
.isDraggable()).toBe(true);
expect(new XBlockInfo({'category': 'chapter', 'actions': {'childAddable':true}})
.isChildAddable()).toBe(true);
});
it('displays icons e.g. trash icon, drag when actions are undefined', function(){
expect(new XBlockInfo({'category': 'chapter', 'actions': {}})
.isDeletable()).toBe(true);
expect(new XBlockInfo({'category': 'chapter', 'actions': {}})
.isDraggable()).toBe(true);
expect(new XBlockInfo({'category': 'chapter', 'actions': {}})
.isChildAddable()).toBe(true);
});
it('works correct to hide header content', function(){
expect(new XBlockInfo({'category': 'sequential', 'is_header_visible': false})
.isHeaderVisible()).toBe(false);
});
it('works correct to show header content when is_header_visible is not defined', function() {
expect(new XBlockInfo({'category': 'sequential', 'actions': {'deletable': true}})
.isHeaderVisible()).toBe(true);
});
});
}
);

View File

@@ -8,7 +8,7 @@ define(["jquery", "sinon", "js/common_helpers/ajax_helpers", "js/views/utils/vie
getItemsOfType, getItemHeaders, verifyItemsExpanded, expandItemsAndVerifyState,
collapseItemsAndVerifyState, createMockCourseJSON, createMockSectionJSON, createMockSubsectionJSON,
verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, mockSingleSectionCourseJSON,
createMockVerticalJSON, createMockIndexJSON,
createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON
mockOutlinePage = readFixtures('mock/mock-course-outline-page.underscore'),
mockRerunNotification = readFixtures('mock/mock-course-rerun-notification.underscore');
@@ -228,6 +228,14 @@ define(["jquery", "sinon", "js/common_helpers/ajax_helpers", "js/views/utils/vie
mockSingleSectionCourseJSON = createMockCourseJSON({}, [
createMockSectionJSON()
]);
mockCourseEntranceExamJSON = createMockCourseJSON({}, [
createMockSectionJSON({}, [
createMockSubsectionJSON({'is_header_visible': false}, [
createMockVerticalJSON()
])
])
]);
});
afterEach(function () {
@@ -259,6 +267,11 @@ define(["jquery", "sinon", "js/common_helpers/ajax_helpers", "js/views/utils/vie
verifyItemsExpanded('subsection', false);
expect(getItemsOfType('unit')).not.toExist();
});
it('unit initially exist for entrance exam', function() {
createCourseOutlinePage(this, mockCourseEntranceExamJSON);
expect(getItemsOfType('unit')).toExist();
});
});
describe("Rerun notification", function () {

View File

@@ -44,6 +44,17 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
this.renderTemplate();
this.addButtonActions(this.$el);
this.addNameEditor();
// For cases in which we need to suppress the header controls during rendering, we'll
// need to add the current model's id/locator to the set of expanded locators
if (this.model.get('is_header_visible') !== null && !this.model.get('is_header_visible')) {
var locator = this.model.get('id');
if(!_.isUndefined(this.expandedLocators) && !this.expandedLocators.contains(locator)) {
this.expandedLocators.add(locator);
this.refresh();
}
}
if (this.shouldRenderChildren() && this.shouldExpandChildren()) {
this.renderChildren();
}