From 5f840e1835470ebccde6810424e03f2d04e6ba59 Mon Sep 17 00:00:00 2001 From: danielghost Date: Fri, 27 Jun 2025 17:45:19 +0100 Subject: [PATCH 1/2] Fix: Add `rawModels` to resolve inconsistency with intersection queries and available subsets (fixes #19). --- js/AdaptModelSet.js | 12 ++++++--- js/ScoringSet.js | 66 ++++++++++++++++++++++++++------------------- js/utils.js | 2 +- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/js/AdaptModelSet.js b/js/AdaptModelSet.js index 57883c4..05f307d 100644 --- a/js/AdaptModelSet.js +++ b/js/AdaptModelSet.js @@ -55,15 +55,22 @@ export default class AdaptModelSet extends ScoringSet { /** * @override */ - get models() { + get rawModels() { return [this.model]; } + /** + * @override + */ + get isAvailable() { + return this.model.get('_isAvailable'); + } + /** * @override */ get isComplete() { - return this._model.get('_isComplete'); + return this.model.get('_isComplete'); } /** @@ -85,4 +92,3 @@ export default class AdaptModelSet extends ScoringSet { */ onPassed() {} } - diff --git a/js/ScoringSet.js b/js/ScoringSet.js index 7df8cf2..7226e9f 100644 --- a/js/ScoringSet.js +++ b/js/ScoringSet.js @@ -207,24 +207,11 @@ export default class ScoringSet extends Backbone.Controller { } /** - * Returns a unique array of models, filtered for `_isAvailable` and intersecting subsets hierarchies - * Always finish by calling `this.filterModels(models)` + * Returns all models regardless of `_isAvailable` * @returns {[Backbone.Model]} */ - get models() { - Logging.error(`models must be overriden for ${this.constructor.name}`); - } - - /** - * Check to see if there are any child models - * @returns {boolean} - */ - get isPopulated() { - return Boolean(this.models?.length); - } - - get isNotPopulated() { - return (this.isPopulated === false); + get rawModels() { + Logging.error(`rawModels must be overriden for ${this.constructor.name}`); } /** @@ -232,7 +219,12 @@ export default class ScoringSet extends Backbone.Controller { * @returns {[ComponentModel]} */ get rawComponents() { - return this.model.findDescendantModels('component'); + return this.rawModels.reduce((components, model) => { + const models = model.isTypeGroup('component') + ? [model] + : model.findDescendantModels('component'); + return components.concat(models); + }, []); } /** @@ -240,7 +232,7 @@ export default class ScoringSet extends Backbone.Controller { * @returns {[QuestionModel]} */ get rawQuestions() { - return this.model.findDescendantModels('question'); + return this.rawComponents.filter(model => model.isTypeGroup('question')); } /** @@ -251,15 +243,21 @@ export default class ScoringSet extends Backbone.Controller { return this.rawComponents.filter(model => !model.isTypeGroup('question')); } + /** + * Returns a unique array of models, filtered for `_isAvailable` and intersecting subsets hierarchies + * Always finish by calling `this.filterModels(models)` + * @returns {[Backbone.Model]} + */ + get models() { + return this.filterModels(this.rawModels); + } + /** * Returns all `_isAvailable` component models * @returns {[ComponentModel]} */ get components() { - return this.models.reduce((components, model) => { - model.isTypeGroup('component') ? components.push(model) : components.push(...model.findDescendantModels('component')); - return components; - }, []).filter(isAvailableInHierarchy); + return this.rawComponents.filter(isAvailableInHierarchy); } /** @@ -275,15 +273,15 @@ export default class ScoringSet extends Backbone.Controller { * @returns {[QuestionModel]} */ get questions() { - return this.components.filter(model => model.isTypeGroup('question')); + return this.rawQuestions.filter(isAvailableInHierarchy); } /** * Returns all `_isAvailable` presentation component models - * @returns {[QuestionModel]} + * @returns {[ComponentModel]} */ get presentationComponents() { - return this.components.filter(model => !model.isTypeGroup('question')); + return this.rawPresentationComponents.filter(isAvailableInHierarchy); } /** @@ -357,7 +355,7 @@ export default class ScoringSet extends Backbone.Controller { * @returns {boolean} */ get canReset() { - return false + return false; } /** @@ -365,7 +363,7 @@ export default class ScoringSet extends Backbone.Controller { * @returns {boolean} */ get isOptional() { - return false + return false; } /** @@ -373,7 +371,7 @@ export default class ScoringSet extends Backbone.Controller { * @returns {boolean} */ get isAvailable() { - return true + return true; } /** @@ -400,6 +398,18 @@ export default class ScoringSet extends Backbone.Controller { return (this.isPassed === false); } + /** + * Check to see if there are any child models + * @returns {boolean} + */ + get isPopulated() { + return Boolean(this.models?.length); + } + + get isNotPopulated() { + return (this.isPopulated === false); + } + /** * Define the objective for reporting purposes * @protected diff --git a/js/utils.js b/js/utils.js index ab94363..e11ed36 100644 --- a/js/utils.js +++ b/js/utils.js @@ -132,7 +132,7 @@ export function getSubsetsByType(type, subsetParent = undefined) { */ export function getSubsetsByModelId(id, subsetParent = undefined) { const models = [Data.findById(id)]; - let sets = getRawSets(subsetParent).filter(set => hasIntersectingHierarchy(set.models, models)); + let sets = getRawSets(subsetParent).filter(set => hasIntersectingHierarchy(set.rawModels, models)); if (subsetParent) { // Create intersection sets between the found sets and the subsetParent sets = sets.map(set => createIntersectionSubset([subsetParent, set])); From 60f87521b5a5d389f4927b2f30225d3100aa5336 Mon Sep 17 00:00:00 2001 From: danielghost Date: Tue, 1 Jul 2025 11:28:20 +0100 Subject: [PATCH 2/2] Update AdaptModelSet availability condition to check the hierarchy rather than just the model. --- js/AdaptModelSet.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/AdaptModelSet.js b/js/AdaptModelSet.js index 05f307d..8934559 100644 --- a/js/AdaptModelSet.js +++ b/js/AdaptModelSet.js @@ -1,4 +1,7 @@ import ScoringSet from './ScoringSet'; +import { + isAvailableInHierarchy +} from './utils'; export default class AdaptModelSet extends ScoringSet { @@ -63,7 +66,7 @@ export default class AdaptModelSet extends ScoringSet { * @override */ get isAvailable() { - return this.model.get('_isAvailable'); + return isAvailableInHierarchy(this.model); } /**