Merge pull request #5764 from edx/dan-f/highlight-active-unit-in-outline
Highlight active unit in studio container page's outline
This commit is contained in:
@@ -88,6 +88,17 @@ define(["jquery", "js/common_helpers/ajax_helpers", "js/common_helpers/template_
|
||||
expect(unitOutlineView.$('.list-units')).toExist();
|
||||
});
|
||||
|
||||
it('highlights the current unit', function() {
|
||||
createUnitOutlineView(this, createMockXBlockInfo('Mock Unit'));
|
||||
$('.outline-unit').each(function(i) {
|
||||
if ($(this).data('locator') === model.get('id')) {
|
||||
expect($(this)).toHaveClass('is-current');
|
||||
} else {
|
||||
expect($(this)).not.toHaveClass('is-current');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('can add a unit', function() {
|
||||
var redirectSpy;
|
||||
createUnitOutlineView(this, createMockXBlockInfo('Mock Unit'));
|
||||
|
||||
@@ -35,15 +35,8 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
|
||||
return !this.model.isVertical();
|
||||
},
|
||||
|
||||
createChildView: function(xblockInfo, parentInfo, parentView) {
|
||||
return new CourseOutlineView({
|
||||
model: xblockInfo,
|
||||
parentInfo: parentInfo,
|
||||
initialState: this.initialState,
|
||||
expandedLocators: this.expandedLocators,
|
||||
template: this.template,
|
||||
parentView: parentView || this
|
||||
});
|
||||
getChildViewClass: function() {
|
||||
return CourseOutlineView;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -112,7 +105,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
|
||||
});
|
||||
// Fetch the full xblock info for the section and then create a view for it
|
||||
sectionInfo.fetch().done(function() {
|
||||
sectionView = self.createChildView(sectionInfo, self.model, self);
|
||||
sectionView = self.createChildView(sectionInfo, self.model, {parentView: self});
|
||||
sectionView.initialState = initialState;
|
||||
sectionView.expandedLocators = self.expandedLocators;
|
||||
sectionView.render();
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
* the ancestors of the unit along with its direct siblings. It also has a single "New Unit"
|
||||
* button to allow a new sibling unit to be added.
|
||||
*/
|
||||
define(['js/views/xblock_outline'],
|
||||
function(XBlockOutlineView) {
|
||||
|
||||
define(['underscore', 'js/views/xblock_outline', 'js/views/unit_outline_child'],
|
||||
function(_, XBlockOutlineView, UnitOutlineChildView) {
|
||||
var UnitOutlineView = XBlockOutlineView.extend({
|
||||
// takes XBlockInfo as a model
|
||||
|
||||
@@ -29,7 +28,11 @@ define(['js/views/xblock_outline'],
|
||||
// i.e. subsection and then section.
|
||||
for (i=ancestors.length - 1; i >= 0; i--) {
|
||||
ancestor = ancestors[i];
|
||||
ancestorView = this.createChildView(ancestor, previousAncestor, ancestorView);
|
||||
ancestorView = this.createChildView(
|
||||
ancestor,
|
||||
previousAncestor,
|
||||
{parentView: ancestorView, currentUnitId: this.model.get('id')}
|
||||
);
|
||||
ancestorView.render();
|
||||
listElement.append(ancestorView.$el);
|
||||
previousAncestor = ancestor;
|
||||
@@ -37,6 +40,17 @@ define(['js/views/xblock_outline'],
|
||||
}
|
||||
}
|
||||
return ancestorView;
|
||||
},
|
||||
|
||||
getChildViewClass: function() {
|
||||
return UnitOutlineChildView;
|
||||
},
|
||||
|
||||
getTemplateContext: function() {
|
||||
return _.extend(
|
||||
XBlockOutlineView.prototype.getTemplateContext.call(this),
|
||||
{currentUnitId: this.model.get('id')}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
34
cms/static/js/views/unit_outline_child.js
Normal file
34
cms/static/js/views/unit_outline_child.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* The UnitOutlineChildView is used to render each Section,
|
||||
* Subsection, and Unit within the Unit Outline component on the unit
|
||||
* page.
|
||||
*/
|
||||
define(['underscore', 'js/views/xblock_outline'],
|
||||
function(_, XBlockOutlineView) {
|
||||
var UnitOutlineChildView = XBlockOutlineView.extend({
|
||||
initialize: function() {
|
||||
XBlockOutlineView.prototype.initialize.call(this);
|
||||
this.currentUnitId = this.options.currentUnitId;
|
||||
},
|
||||
|
||||
getTemplateContext: function() {
|
||||
return _.extend(
|
||||
XBlockOutlineView.prototype.getTemplateContext.call(this),
|
||||
{currentUnitId: this.currentUnitId}
|
||||
);
|
||||
},
|
||||
|
||||
getChildViewClass: function() {
|
||||
return UnitOutlineChildView;
|
||||
},
|
||||
|
||||
createChildView: function(childInfo, parentInfo, options) {
|
||||
options = _.isUndefined(options) ? {} : options;
|
||||
return XBlockOutlineView.prototype.createChildView.call(
|
||||
this, childInfo, parentInfo, _.extend(options, {currentUnitId: this.currentUnitId})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return UnitOutlineChildView;
|
||||
}); // end define()
|
||||
@@ -54,6 +54,15 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
|
||||
},
|
||||
|
||||
renderTemplate: function() {
|
||||
var html = this.template(this.getTemplateContext());
|
||||
if (this.parentInfo) {
|
||||
this.setElement($(html));
|
||||
} else {
|
||||
this.$el.html(html);
|
||||
}
|
||||
},
|
||||
|
||||
getTemplateContext: function() {
|
||||
var xblockInfo = this.model,
|
||||
childInfo = xblockInfo.get('child_info'),
|
||||
parentInfo = this.parentInfo,
|
||||
@@ -62,7 +71,6 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
|
||||
parentType = parentInfo ? XBlockViewUtils.getXBlockType(parentInfo.get('category')) : null,
|
||||
addChildName = null,
|
||||
defaultNewChildName = null,
|
||||
html,
|
||||
isCollapsed = this.shouldRenderChildren() && !this.shouldExpandChildren();
|
||||
if (childInfo) {
|
||||
addChildName = interpolate(gettext('New %(component_type)s'), {
|
||||
@@ -70,7 +78,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
|
||||
}, true);
|
||||
defaultNewChildName = childInfo.display_name;
|
||||
}
|
||||
html = this.template({
|
||||
return {
|
||||
xblockInfo: xblockInfo,
|
||||
visibilityClass: XBlockViewUtils.getXBlockVisibilityClass(xblockInfo.get('visibility_state')),
|
||||
typeListClass: XBlockViewUtils.getXBlockListTypeClass(xblockType),
|
||||
@@ -86,20 +94,15 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
|
||||
includesChildren: this.shouldRenderChildren(),
|
||||
hasExplicitStaffLock: this.model.get('has_explicit_staff_lock'),
|
||||
staffOnlyMessage: this.model.get('staff_only_message')
|
||||
});
|
||||
if (this.parentInfo) {
|
||||
this.setElement($(html));
|
||||
} else {
|
||||
this.$el.html(html);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
renderChildren: function() {
|
||||
var self = this,
|
||||
xblockInfo = this.model;
|
||||
if (xblockInfo.get('child_info')) {
|
||||
_.each(this.model.get('child_info').children, function(child) {
|
||||
var childOutlineView = self.createChildView(child, xblockInfo);
|
||||
parentInfo = this.model;
|
||||
if (parentInfo.get('child_info')) {
|
||||
_.each(this.model.get('child_info').children, function(childInfo) {
|
||||
var childOutlineView = self.createChildView(childInfo, parentInfo);
|
||||
childOutlineView.render();
|
||||
self.addChildView(childOutlineView);
|
||||
});
|
||||
@@ -182,15 +185,20 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
|
||||
return true;
|
||||
},
|
||||
|
||||
createChildView: function(xblockInfo, parentInfo, parentView) {
|
||||
return new XBlockOutlineView({
|
||||
model: xblockInfo,
|
||||
getChildViewClass: function() {
|
||||
return XBlockOutlineView;
|
||||
},
|
||||
|
||||
createChildView: function(childInfo, parentInfo, options) {
|
||||
var viewClass = this.getChildViewClass();
|
||||
return new viewClass(_.extend({
|
||||
model: childInfo,
|
||||
parentInfo: parentInfo,
|
||||
parentView: this,
|
||||
initialState: this.initialState,
|
||||
expandedLocators: this.expandedLocators,
|
||||
template: this.template,
|
||||
parentView: parentView || this
|
||||
});
|
||||
template: this.template
|
||||
}, options));
|
||||
},
|
||||
|
||||
onSync: function(event) {
|
||||
|
||||
@@ -373,7 +373,7 @@ $outline-indent-width: $baseline;
|
||||
}
|
||||
|
||||
.item-title a {
|
||||
color: $color-heading-base;
|
||||
color: $color-heading-base;
|
||||
|
||||
&:hover {
|
||||
color: $blue;
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
|
||||
.widget-layout dl#brain_buster_captcha dd #captcha_answer {
|
||||
display: block;
|
||||
width: 97%%;
|
||||
width: 97%;
|
||||
}
|
||||
|
||||
.widget-layout .form-actions .btn-post_topic {
|
||||
|
||||
@@ -262,6 +262,47 @@
|
||||
|
||||
.item-title {
|
||||
@extend %cont-text-wrap;
|
||||
|
||||
a {
|
||||
color: $blue;
|
||||
|
||||
&:hover {
|
||||
color: $orange-d1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: is current item being edited/viewed
|
||||
.is-current {
|
||||
background: $gray-l4;
|
||||
|
||||
.unit-title a {
|
||||
@extend %ui-disabled;
|
||||
@extend %t-strong;
|
||||
color: $color-heading-base;
|
||||
}
|
||||
}
|
||||
|
||||
// typographical overrides (based off of outline-simple)
|
||||
.section-header, .subsection-header {
|
||||
line-height: 0;
|
||||
margin-bottom: ($baseline/2);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
border-bottom: 1px solid $gray-l4;
|
||||
padding-bottom: ($baseline/2);
|
||||
}
|
||||
|
||||
// subsections overrides (based off of outline-simple)
|
||||
.outline-subsection {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// units overrides (based off of outline-simple)
|
||||
.outline-unit {
|
||||
padding: 3px 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% if (parentInfo) { %>
|
||||
<li class="outline-item outline-<%= xblockType %> <%= visibilityClass %>"
|
||||
<li class="outline-item outline-<%= xblockType %> <%= visibilityClass %> <%= xblockInfo.get('id') === currentUnitId ? 'is-current' : '' %>"
|
||||
data-parent="<%= parentInfo.get('id') %>" data-locator="<%= xblockInfo.get('id') %>">
|
||||
<div class="<%= xblockType %>-header">
|
||||
<h3 class="<%= xblockType %>-header-details">
|
||||
|
||||
Reference in New Issue
Block a user