Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Updated completionCalculations.js (fixes #10) #11

Merged
merged 2 commits into from
Dec 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 97 additions & 105 deletions js/completionCalculations.js
Original file line number Diff line number Diff line change
@@ -1,149 +1,141 @@
// duplicate of pagelevelprogress completionCalculations.js v5.1.0
define([
'core/js/adapt'
], function(Adapt) {

var Completion = Backbone.Controller.extend({

subProgressCompleted: 0,
subProgressTotal: 0,
nonAssessmentCompleted: 0,
nonAssessmentTotal: 0,
assessmentCompleted: 0,
assessmentTotal: 0

});
import Adapt from 'core/js/adapt';
import _ from 'underscore';

class Completion extends Backbone.Controller {

initialize() {
_.bindAll(this, 'calculatePercentageComplete');
this.subProgressCompleted = 0;
this.subProgressTotal = 0;
this.nonAssessmentCompleted = 0;
this.nonAssessmentTotal = 0;
this.assessmentCompleted = 0;
this.assessmentTotal = 0;
}

// Calculate completion of a contentObject
function calculateCompletion(contentObjectModel) {

var completion = new Completion();

var viewType = contentObjectModel.get('_type');
var isComplete = contentObjectModel.get('_isComplete') ? 1 : 0;
var children;

switch (viewType) {
case 'page':
// If it's a page
children = contentObjectModel.getAllDescendantModels().filter(function(model) {
return model.get('_isAvailable') && !model.get('_isOptional');
});

var availableChildren = filterAvailableChildren(children);
var components = getPageLevelProgressEnabledModels(availableChildren);

var nonAssessmentComponents = getNonAssessmentComponents(components);

completion.nonAssessmentTotal = nonAssessmentComponents.length;
completion.nonAssessmentCompleted = getComponentsCompleted(nonAssessmentComponents).length;

var assessmentComponents = getAssessmentComponents(components);

completion.assessmentTotal = assessmentComponents.length;
completion.assessmentCompleted = getComponentsInteractionCompleted(assessmentComponents).length;

if (contentObjectModel.get('_pageLevelProgress')._excludeAssessments !== true) {
completion.subProgressCompleted = contentObjectModel.get('_subProgressComplete') || 0;
completion.subProgressTotal = contentObjectModel.get('_subProgressTotal') || 0;
calculateCompletion(contentObjectModel, setGlobal = false) {
const completion = {};
const perform = contentObjectModel => {
const viewType = contentObjectModel.get('_type');
const isComplete = contentObjectModel.get('_isComplete') ? 1 : 0;
let children;
switch (viewType) {
case 'page': {
// If it's a page
children = contentObjectModel.getAllDescendantModels().filter(model => {
return model.get('_isAvailable') && !model.get('_isOptional');
});

const availableChildren = this.filterAvailableChildren(children);
const components = this.getPageLevelProgressEnabledModels(availableChildren);
const nonAssessmentComponents = this.getNonAssessmentComponents(components);

completion.nonAssessmentTotal += nonAssessmentComponents.length;
completion.nonAssessmentCompleted += this.getComponentsCompleted(nonAssessmentComponents).length;

const assessmentComponents = this.getAssessmentComponents(components);

completion.assessmentTotal += assessmentComponents.length;
completion.assessmentCompleted += this.getComponentsInteractionCompleted(assessmentComponents).length;

if (contentObjectModel.get('_pageLevelProgress')?._excludeAssessments !== true) {
completion.subProgressCompleted += contentObjectModel.get('_subProgressComplete') || 0;
completion.subProgressTotal += contentObjectModel.get('_subProgressTotal') || 0;
}

const showPageCompletionCourse = Adapt.course.get('_pageLevelProgress')?._showPageCompletion !== false;
const showPageCompletionPage = contentObjectModel.get('_pageLevelProgress')?._showPageCompletion !== false;

if (showPageCompletionCourse && showPageCompletionPage) {
// optionally add one point extra for page completion to eliminate incomplete pages and full progress bars
// if _showPageCompletion is true then the progress bar should also consider it so add 1 to nonAssessmentTotal
completion.nonAssessmentCompleted += isComplete;
completion.nonAssessmentTotal += 1;
}

break;
}

var showPageCompletionCourse = Adapt.course.get('_pageLevelProgress') && Adapt.course.get('_pageLevelProgress')._showPageCompletion !== false;
var showPageCompletionPage = contentObjectModel.get('_pageLevelProgress') && contentObjectModel.get('_pageLevelProgress')._showPageCompletion !== false;

if (showPageCompletionCourse && showPageCompletionPage) {
// optionally add one point extra for page completion to eliminate incomplete pages and full progress bars
// if _showPageCompletion is true then the progress bar should also consider it so add 1 to nonAssessmentTotal
completion.nonAssessmentCompleted += isComplete;
completion.nonAssessmentTotal += 1;
case 'menu': case 'course': {
// If it's a sub-menu
children = contentObjectModel.getChildren().models;
children.forEach(perform);
break;
}

break;
case 'menu': case 'course':
// If it's a sub-menu
children = contentObjectModel.get('_children').models;
children.forEach(function(contentObject) {
var completionObject = calculateCompletion(contentObject);
completion.subProgressCompleted += completionObject.subProgressCompleted || 0;
completion.subProgressTotal += completionObject.subProgressTotal || 0;
completion.nonAssessmentTotal += completionObject.nonAssessmentTotal;
completion.nonAssessmentCompleted += completionObject.nonAssessmentCompleted;
completion.assessmentTotal += completionObject.assessmentTotal;
completion.assessmentCompleted += completionObject.assessmentCompleted;
});
break;

}

}
};
completion.subProgressCompleted = 0;
completion.subProgressTotal = 0;
completion.nonAssessmentTotal = 0;
completion.nonAssessmentCompleted = 0;
completion.assessmentTotal = 0;
completion.assessmentCompleted = 0;
perform(contentObjectModel);
if (setGlobal) Object.assign(Adapt.tocCompletion, completion);
return completion;
}

function getNonAssessmentComponents(models) {
return models.filter(function(model) {
getNonAssessmentComponents(models) {
return models.filter(model => {
return !model.get('_isPartOfAssessment');
});
}

function getAssessmentComponents(models) {
return models.filter(function(model) {
getAssessmentComponents(models) {
return models.filter(model => {
return model.get('_isPartOfAssessment');
});
}

function getComponentsCompleted(models) {
return models.filter(function(item) {
getComponentsCompleted(models) {
return models.filter(item => {
return item.get('_isComplete');
});
}

function getComponentsInteractionCompleted(models) {
return models.filter(function(item) {
getComponentsInteractionCompleted(models) {
return models.filter(item => {
return item.get('_isComplete');
});
}

//Get only those models who were enabled for pageLevelProgress
function getPageLevelProgressEnabledModels(models) {
return models.filter(function(model) {
var config = model.get('_pageLevelProgress');
return config && config._isEnabled;
// Get only those models who were enabled for pageLevelProgress
getPageLevelProgressEnabledModels(models) {
return models.filter(model => {
const config = model.get('_pageLevelProgress');
return config?._isEnabled;
});
}

function unavailableInHierarchy(parents) {
unavailableInHierarchy(parents) {
if (!parents) return;
return parents.some(function(parent) {
return parents.some(parent => {
return !parent.get('_isAvailable');
});
}

function filterAvailableChildren(children) {
var availableChildren = [];
filterAvailableChildren(children) {
const availableChildren = [];

for (var i = 0, count = children.length; i < count; i++) {
var parents = children[i].getAncestorModels();
if (unavailableInHierarchy(parents)) continue;
for (let i = 0, count = children.length; i < count; i++) {
const parents = children[i].getAncestorModels();
if (this.unavailableInHierarchy(parents)) continue;
availableChildren.push(children[i]);
}

return availableChildren;
}

function calculatePercentageComplete(model) {
var completionObject = calculateCompletion(model);
calculatePercentageComplete(model, setGlobal = false) {
const completionObject = this.calculateCompletion(model, setGlobal);
// take all assessment, nonassessment and subprogress into percentage
// this allows the user to see if assessments have been passed, if assessment components can be retaken, and all other component's completion
var completed = completionObject.nonAssessmentCompleted + completionObject.assessmentCompleted + completionObject.subProgressCompleted;
var total = completionObject.nonAssessmentTotal + completionObject.assessmentTotal + completionObject.subProgressTotal;
var percentageComplete = Math.floor((completed / total)*100);
const completed = completionObject.nonAssessmentCompleted + completionObject.assessmentCompleted + completionObject.subProgressCompleted;
const total = completionObject.nonAssessmentTotal + completionObject.assessmentTotal + completionObject.subProgressTotal;
const percentageComplete = Math.floor((completed / total) * 100);
return percentageComplete;
}

return {
calculateCompletion: calculateCompletion,
calculatePercentageComplete: calculatePercentageComplete,
getPageLevelProgressEnabledModels: getPageLevelProgressEnabledModels,
filterAvailableChildren: filterAvailableChildren
};
}

});
export default (Adapt.tocCompletion = new Completion());