diff --git a/cms/static/js/spec/views/unit_outline_spec.js b/cms/static/js/spec/views/unit_outline_spec.js index 085cb36202..d0205dc445 100644 --- a/cms/static/js/spec/views/unit_outline_spec.js +++ b/cms/static/js/spec/views/unit_outline_spec.js @@ -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')); diff --git a/cms/static/js/views/course_outline.js b/cms/static/js/views/course_outline.js index d693bd5aee..1a5e26dde4 100644 --- a/cms/static/js/views/course_outline.js +++ b/cms/static/js/views/course_outline.js @@ -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(); diff --git a/cms/static/js/views/unit_outline.js b/cms/static/js/views/unit_outline.js index cea6b91b68..041986a4a6 100644 --- a/cms/static/js/views/unit_outline.js +++ b/cms/static/js/views/unit_outline.js @@ -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')} + ); } }); diff --git a/cms/static/js/views/unit_outline_child.js b/cms/static/js/views/unit_outline_child.js new file mode 100644 index 0000000000..f327c6367e --- /dev/null +++ b/cms/static/js/views/unit_outline_child.js @@ -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() diff --git a/cms/static/js/views/xblock_outline.js b/cms/static/js/views/xblock_outline.js index 8d92da1dc9..23f7e7694e 100644 --- a/cms/static/js/views/xblock_outline.js +++ b/cms/static/js/views/xblock_outline.js @@ -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) { diff --git a/cms/static/sass/elements/_modules.scss b/cms/static/sass/elements/_modules.scss index 421f97ff29..dfbad361d9 100644 --- a/cms/static/sass/elements/_modules.scss +++ b/cms/static/sass/elements/_modules.scss @@ -373,7 +373,7 @@ $outline-indent-width: $baseline; } .item-title a { - color: $color-heading-base; + color: $color-heading-base; &:hover { color: $blue; diff --git a/cms/static/sass/elements/_tender-widget.scss b/cms/static/sass/elements/_tender-widget.scss index 056bb405b3..e1ef119252 100644 --- a/cms/static/sass/elements/_tender-widget.scss +++ b/cms/static/sass/elements/_tender-widget.scss @@ -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 { diff --git a/cms/static/sass/views/_container.scss b/cms/static/sass/views/_container.scss index 7a2163939c..7780d04850 100644 --- a/cms/static/sass/views/_container.scss +++ b/cms/static/sass/views/_container.scss @@ -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; } } } diff --git a/cms/templates/js/unit-outline.underscore b/cms/templates/js/unit-outline.underscore index b4cfc66c26..9579a81150 100644 --- a/cms/templates/js/unit-outline.underscore +++ b/cms/templates/js/unit-outline.underscore @@ -1,5 +1,5 @@ <% if (parentInfo) { %> -