feat: make hide from TOC a visibility section setting (#33952)
Exposes the hide_from_toc xblock attribute so course authors can configure it as a section visibility option in Studio. Before this change, the Hide from TOC functionality was mainly used by OLX components. Hence, it wasn't available for configuration through the Studio UI. Still, its implementation existed in the platform and could be used by setting the attribute: hide_from_toc=true as part of the OLX definition. Ref: https://openedx.atlassian.net/wiki/spaces/OEPM/pages/3853975595/Feature+Enhancement+Proposal+Hide+Sections+from+course+outline
This commit is contained in:
@@ -177,6 +177,14 @@ define(
|
||||
* List of tags of the unit. This list is managed by the content_tagging module.
|
||||
*/
|
||||
tags: null,
|
||||
/**
|
||||
* True if the xblock is not visible to students only via links.
|
||||
*/
|
||||
hide_from_toc: null,
|
||||
/**
|
||||
* True iff this xblock should display a "Contains staff only content" message.
|
||||
*/
|
||||
hide_from_toc_message: null,
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
|
||||
@@ -42,6 +42,8 @@ describe('CourseOutlinePage', function() {
|
||||
user_partition_info: {},
|
||||
highlights_enabled: true,
|
||||
highlights_enabled_for_messaging: false,
|
||||
hide_from_toc: false,
|
||||
enable_hide_from_toc_ui: true
|
||||
}, options, {child_info: {children: children}});
|
||||
};
|
||||
|
||||
@@ -68,7 +70,9 @@ describe('CourseOutlinePage', function() {
|
||||
show_review_rules: true,
|
||||
user_partition_info: {},
|
||||
highlights_enabled: true,
|
||||
highlights_enabled_for_messaging: false
|
||||
highlights_enabled_for_messaging: false,
|
||||
hide_from_toc: false,
|
||||
enable_hide_from_toc_ui: true
|
||||
}, options, {child_info: {children: children}});
|
||||
};
|
||||
|
||||
@@ -93,7 +97,9 @@ describe('CourseOutlinePage', function() {
|
||||
group_access: {},
|
||||
user_partition_info: {},
|
||||
highlights: [],
|
||||
highlights_enabled: true
|
||||
highlights_enabled: true,
|
||||
hide_from_toc: false,
|
||||
enable_hide_from_toc_ui: true
|
||||
}, options, {child_info: {children: children}});
|
||||
};
|
||||
|
||||
@@ -123,7 +129,9 @@ describe('CourseOutlinePage', function() {
|
||||
},
|
||||
user_partitions: [],
|
||||
group_access: {},
|
||||
user_partition_info: {}
|
||||
user_partition_info: {},
|
||||
hide_from_toc: false,
|
||||
enable_hide_from_toc_ui: true
|
||||
}, options, {child_info: {children: children}});
|
||||
};
|
||||
|
||||
@@ -141,7 +149,9 @@ describe('CourseOutlinePage', function() {
|
||||
edited_by: 'MockUser',
|
||||
user_partitions: [],
|
||||
group_access: {},
|
||||
user_partition_info: {}
|
||||
user_partition_info: {},
|
||||
hide_from_toc: false,
|
||||
enable_hide_from_toc_ui: true
|
||||
}, options);
|
||||
};
|
||||
|
||||
@@ -1214,7 +1224,9 @@ describe('CourseOutlinePage', function() {
|
||||
is_practice_exam: false,
|
||||
is_proctored_exam: false,
|
||||
default_time_limit_minutes: 150,
|
||||
hide_after_due: true
|
||||
hide_after_due: true,
|
||||
hide_from_toc: false,
|
||||
enable_hide_from_toc_ui: true,
|
||||
}, [
|
||||
createMockVerticalJSON({
|
||||
has_changes: true,
|
||||
@@ -1397,6 +1409,7 @@ describe('CourseOutlinePage', function() {
|
||||
default_time_limit_minutes: 150,
|
||||
hide_after_due: true,
|
||||
is_onboarding_exam: false,
|
||||
hide_from_toc: null,
|
||||
}
|
||||
});
|
||||
expect(requests[0].requestHeaders['X-HTTP-Method-Override']).toBe('PATCH');
|
||||
@@ -2240,6 +2253,8 @@ describe('CourseOutlinePage', function() {
|
||||
is_practice_exam: false,
|
||||
is_proctored_exam: false,
|
||||
default_time_limit_minutes: null,
|
||||
hide_from_toc: false,
|
||||
enable_hide_from_toc_ui: true,
|
||||
}, [
|
||||
createMockVerticalJSON({
|
||||
has_changes: true,
|
||||
@@ -2521,6 +2536,7 @@ describe('CourseOutlinePage', function() {
|
||||
publish: 'republish',
|
||||
metadata: {
|
||||
visible_to_staff_only: null,
|
||||
hide_from_toc: null
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -314,6 +314,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
|
||||
var isProctoredExam = xblockInfo.get('is_proctored_exam');
|
||||
var isPracticeExam = xblockInfo.get('is_practice_exam');
|
||||
var isOnboardingExam = xblockInfo.get('is_onboarding_exam');
|
||||
var enableHideFromTOCUI = xblockInfo.get('enable_hide_from_toc_ui');
|
||||
var hideFromTOC = xblockInfo.get('hide_from_toc');
|
||||
var html = this.template($.extend({}, {
|
||||
xblockInfo: xblockInfo,
|
||||
xblockType: this.options.xblockType,
|
||||
@@ -323,6 +325,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
|
||||
isProctoredExam: isProctoredExam,
|
||||
isPracticeExam: isPracticeExam,
|
||||
isOnboardingExam: isOnboardingExam,
|
||||
enableHideFromTOCUI: enableHideFromTOCUI,
|
||||
hideFromTOC: hideFromTOC,
|
||||
isTimedExam: isTimeLimited && !(
|
||||
isProctoredExam || isPracticeExam || isOnboardingExam
|
||||
),
|
||||
@@ -798,6 +802,10 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
|
||||
return this.model.get('ancestor_has_staff_lock');
|
||||
},
|
||||
|
||||
isModelHiddenFromTOC: function() {
|
||||
return this.model.get('hide_from_toc');
|
||||
},
|
||||
|
||||
getContext: function() {
|
||||
return {
|
||||
hasExplicitStaffLock: this.isModelLocked(),
|
||||
@@ -812,6 +820,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
|
||||
afterRender: function() {
|
||||
AbstractVisibilityEditor.prototype.afterRender.call(this);
|
||||
this.setLock(this.isModelLocked());
|
||||
this.setHideFromTOC(this.isModelHiddenFromTOC());
|
||||
this.setVisibleToLearners(this.isVisibleToLearners());
|
||||
},
|
||||
|
||||
setLock: function(value) {
|
||||
@@ -822,8 +832,24 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
|
||||
return this.$('#staff_lock').is(':checked');
|
||||
},
|
||||
|
||||
setHideFromTOC: function(value) {
|
||||
this.$('#hide_from_toc').prop('checked', value);
|
||||
},
|
||||
|
||||
setVisibleToLearners: function(value) {
|
||||
this.$('#visible_to_learners').prop('checked', value);
|
||||
},
|
||||
|
||||
isVisibleToLearners: function() {
|
||||
return this.$('#staff_lock').is(':not(:checked)') && this.$('#hide_from_toc').is(':not(:checked)');
|
||||
},
|
||||
|
||||
isHiddenFromTOC: function() {
|
||||
return this.$('#hide_from_toc').is(':checked');
|
||||
},
|
||||
|
||||
hasChanges: function() {
|
||||
return this.isModelLocked() !== this.isLocked();
|
||||
return this.isModelLocked() !== this.isLocked() || this.isModelHiddenFromTOC() !== this.isHiddenFromTOC();
|
||||
},
|
||||
|
||||
getRequestData: function() {
|
||||
@@ -831,7 +857,8 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
|
||||
return {
|
||||
publish: 'republish',
|
||||
metadata: {
|
||||
visible_to_staff_only: this.isLocked() ? true : null
|
||||
visible_to_staff_only: this.isLocked() || null,
|
||||
hide_from_toc: this.isHiddenFromTOC() || null
|
||||
}
|
||||
};
|
||||
} else {
|
||||
@@ -1055,12 +1082,20 @@ define(['jquery', 'backbone', 'underscore', 'gettext', 'js/views/baseview',
|
||||
if (this.currentVisibility() === 'staff_only') {
|
||||
metadata.visible_to_staff_only = true;
|
||||
metadata.hide_after_due = null;
|
||||
metadata.hide_from_toc = null;
|
||||
} else if (this.currentVisibility() === 'hide_after_due') {
|
||||
metadata.visible_to_staff_only = null;
|
||||
metadata.hide_after_due = true;
|
||||
} else {
|
||||
metadata.hide_from_toc = null;
|
||||
} else if (this.currentVisibility() === 'hide_from_toc'){
|
||||
metadata.visible_to_staff_only = null;
|
||||
metadata.hide_after_due = null;
|
||||
metadata.hide_from_toc = true;
|
||||
}
|
||||
else {
|
||||
metadata.visible_to_staff_only = null;
|
||||
metadata.hide_after_due = null;
|
||||
metadata.hide_from_toc = null;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -149,6 +149,7 @@ function($, _, gettext, BaseView, ViewUtils, XBlockViewUtils, MoveXBlockUtils, H
|
||||
releaseDate: this.model.get('release_date'),
|
||||
releaseDateFrom: this.model.get('release_date_from'),
|
||||
hasExplicitStaffLock: this.model.get('has_explicit_staff_lock'),
|
||||
hideFromTOC: this.model.get('hide_from_toc'),
|
||||
staffLockFrom: this.model.get('staff_lock_from'),
|
||||
enableCopyUnit: this.model.get('enable_copy_paste_units'),
|
||||
course: window.course,
|
||||
|
||||
@@ -29,6 +29,8 @@ function($, _, gettext, ViewUtils, ModuleUtils, XBlockInfo, StringUtils) {
|
||||
*
|
||||
* staffOnly - all of the block's content is to be shown to staff only
|
||||
* Note: staff only items do not affect their parent's state.
|
||||
*
|
||||
* hideFromTOC - all of the block's content is to be hidden from the table of contents.
|
||||
*/
|
||||
VisibilityState = {
|
||||
live: 'live',
|
||||
@@ -36,7 +38,8 @@ function($, _, gettext, ViewUtils, ModuleUtils, XBlockInfo, StringUtils) {
|
||||
unscheduled: 'unscheduled',
|
||||
needsAttention: 'needs_attention',
|
||||
staffOnly: 'staff_only',
|
||||
gated: 'gated'
|
||||
gated: 'gated',
|
||||
hideFromTOC: 'hide_from_toc'
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -310,6 +313,9 @@ function($, _, gettext, ViewUtils, ModuleUtils, XBlockInfo, StringUtils) {
|
||||
if (visibilityState === VisibilityState.staffOnly) {
|
||||
return 'is-staff-only';
|
||||
}
|
||||
if (visibilityState === VisibilityState.hideFromTOC) {
|
||||
return 'is-hidden-from-toc';
|
||||
}
|
||||
if (visibilityState === VisibilityState.gated) {
|
||||
return 'is-gated';
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ function($, _, gettext, BaseView, ViewUtils, XBlockViewUtils, XBlockStringFieldE
|
||||
includesChildren: this.shouldRenderChildren(),
|
||||
hasExplicitStaffLock: this.model.get('has_explicit_staff_lock'),
|
||||
staffOnlyMessage: this.model.get('staff_only_message'),
|
||||
hideFromTOCMessage: this.model.get('hide_from_toc_message'),
|
||||
course: course,
|
||||
enableCopyPasteUnits: this.model.get("enable_copy_paste_units"), // ENABLE_COPY_PASTE_UNITS waffle flag
|
||||
useTaggingTaxonomyListPage: this.model.get("use_tagging_taxonomy_list_page"), // ENABLE_TAGGING_TAXONOMY_LIST_PAGE waffle flag
|
||||
|
||||
@@ -507,6 +507,18 @@ $outline-indent-width: $baseline;
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: is hidden from TOC
|
||||
&.is-hidden-from-toc {
|
||||
// needed to make sure direct children only
|
||||
> .section-status,
|
||||
> .subsection-status,
|
||||
> .unit-status {
|
||||
.status-message .icon {
|
||||
color: $color-hide-from-toc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: has gated content
|
||||
&.is-gated {
|
||||
|
||||
@@ -603,6 +615,11 @@ $outline-indent-width: $baseline;
|
||||
border-left-color: $color-staff-only;
|
||||
}
|
||||
|
||||
// CASE: is hidden from TOC
|
||||
&.is-hidden-from-toc {
|
||||
border-left-color: $color-hide-from-toc;
|
||||
}
|
||||
|
||||
// CASE: has gated content
|
||||
&.is-gated {
|
||||
border-left-color: $color-gated;
|
||||
@@ -698,6 +715,11 @@ $outline-indent-width: $baseline;
|
||||
border-left-color: $color-staff-only;
|
||||
}
|
||||
|
||||
// CASE: is hidden from TOC
|
||||
&.is-hidden-from-toc {
|
||||
border-left-color: $color-hide-from-toc;
|
||||
}
|
||||
|
||||
// CASE: is presented for gated
|
||||
&.is-gated {
|
||||
border-left-color: $color-gated;
|
||||
|
||||
@@ -218,6 +218,7 @@ $color-ready: $green !default;
|
||||
$color-warning: $orange-l2 !default;
|
||||
$color-error: $red-l2 !default;
|
||||
$color-staff-only: $black !default;
|
||||
$color-hide-from-toc: $black !default;
|
||||
$color-gated: $black !default;
|
||||
|
||||
$color-heading-base: $gray-d2 !default;
|
||||
|
||||
@@ -155,6 +155,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: is hidden from TOC
|
||||
&.is-hidden-from-toc{
|
||||
@extend %bar-module-black;
|
||||
|
||||
&.is-scheduled .wrapper-release .copy {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
}
|
||||
|
||||
// CASE: content is gated
|
||||
&.is-gated {
|
||||
@extend %bar-module-black;
|
||||
|
||||
Reference in New Issue
Block a user