diff --git a/js/PageLevelProgressIndicatorView.js b/js/PageLevelProgressIndicatorView.js
index cb8902d..604f188 100644
--- a/js/PageLevelProgressIndicatorView.js
+++ b/js/PageLevelProgressIndicatorView.js
@@ -57,7 +57,8 @@ class PageLevelProgressIndicatorView extends Backbone.View {
if (isPresentationComponentWithItems) {
const children = this.model.getChildren();
const visited = children.filter(child => child.get('_isVisited'));
- return Math.round(visited.length / children.length * 100);
+ // Handle division by zero when component has no children
+ return children.length === 0 ? 0 : Math.round(visited.length / children.length * 100);
}
return 0;
}
@@ -98,6 +99,8 @@ class PageLevelProgressIndicatorView extends Backbone.View {
const data = this.model.toJSON();
data.ariaLabel = this.ariaLabel;
data.type = this.type;
+ data._globals = Adapt.course.get('_globals');
+ data._isOptional = this.model.get('_isOptional') || false;
return data;
}
diff --git a/js/completionCalculations.js b/js/completionCalculations.js
index 1218b63..6c8d539 100644
--- a/js/completionCalculations.js
+++ b/js/completionCalculations.js
@@ -132,7 +132,8 @@ class Completion extends Backbone.Controller {
// this allows the user to see if assessments have been passed, if assessment components can be retaken, and all other component's completion
const completed = completionObject.nonAssessmentCompleted + completionObject.assessmentCompleted + completionObject.subProgressCompleted;
const total = completionObject.nonAssessmentTotal + completionObject.assessmentTotal + completionObject.subProgressTotal;
- const percentageComplete = Math.floor((completed / total) * 100);
+ // Handle division by zero when page contains only optional content
+ const percentageComplete = total === 0 ? 0 : Math.floor((completed / total) * 100);
return percentageComplete;
}
diff --git a/less/pageLevelProgressIndicator.less b/less/pageLevelProgressIndicator.less
index 51f8938..f2e29c2 100644
--- a/less/pageLevelProgressIndicator.less
+++ b/less/pageLevelProgressIndicator.less
@@ -1,6 +1,18 @@
// Global indicator
// --------------------------------------------------
.pagelevelprogress {
+ &__indicator-outer {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ &__indicator-group {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
&__indicator {
display: flex;
width: 2rem;
@@ -28,7 +40,12 @@
width: var(--adapt-pagelevelprogress-percentage);
}
- &__indicator .js-indicator-aria-label {
- top: 0;
+ &__indicator-label {
+ font-size: 0.5rem;
+ font-weight: normal;
+ text-align: center;
+ margin-top: 0.125rem;
+ line-height: 1;
+ white-space: nowrap;
}
}
diff --git a/templates/pageLevelProgressIndicator.jsx b/templates/pageLevelProgressIndicator.jsx
index 3701672..2b1bcc8 100644
--- a/templates/pageLevelProgressIndicator.jsx
+++ b/templates/pageLevelProgressIndicator.jsx
@@ -3,9 +3,40 @@ import { compile } from 'core/js/reactHelpers';
export default function PageLevelProgressIndicator (props) {
const {
- ariaLabel
+ ariaLabel,
+ _isOptional
} = props;
+ // Build aria-label with optional prefix if needed
+ const compiledAriaLabel = ariaLabel ? compile(ariaLabel, props) : '';
+ const optionalLabel = props._globals?._accessibility?._ariaLabels?.optional || 'Optional';
+ const fullAriaLabel = _isOptional ? `${optionalLabel}. ${compiledAriaLabel}` : compiledAriaLabel;
+
+ // Only render wrapper group when optional label exists
+ if (_isOptional) {
+ return (
+
+
+
+
+
+
+ {ariaLabel &&
+
+ {fullAriaLabel}
+
+ }
+
+
+
+
+
+ {optionalLabel}
+
+
+ );
+ }
+
return (
@@ -14,7 +45,7 @@ export default function PageLevelProgressIndicator (props) {
{ariaLabel &&
- {compile(ariaLabel, props)}
+ {fullAriaLabel}
}