From a059dcb3aaaf4781b91bfb556e9fd93fa916392f Mon Sep 17 00:00:00 2001 From: Chris Steele Date: Wed, 19 Jun 2024 12:51:54 +0100 Subject: [PATCH 1/6] Respect locked content when returning to location --- js/adapt-contrib-bookmarking.js | 45 ++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/js/adapt-contrib-bookmarking.js b/js/adapt-contrib-bookmarking.js index 1924f65..96975bd 100644 --- a/js/adapt-contrib-bookmarking.js +++ b/js/adapt-contrib-bookmarking.js @@ -88,8 +88,8 @@ class Bookmarking extends Backbone.Controller { resumeButtonAriaLabel } = this.globals._extensions._bookmarking; const $target = $(event.target); - const label = $target.attr('label') || $target.html() || resumeButtonText || null; - const ariaLabel = $target.attr('aria-label') || resumeButtonAriaLabel || null; + const label = $target.attr('label') || $target.html() || resumeButtonText || null; + const ariaLabel = $target.attr('aria-label') || resumeButtonAriaLabel || null; const _location = $target.attr('location') || this.location; const id = this.getLocationId(_location); const isDisabled = ['', undefined, 'current'].includes(id); @@ -171,13 +171,52 @@ class Bookmarking extends Backbone.Controller { }); } + /** + * If the bookmark is preceded by locked content then find the nearest appropriate location + * @param {string} id the bookmarked location + * @returns the identifier of the location to return the user + */ + getAppropriateReturnPath(id) { + const model = data.findById(id); + let target = id; + + if (model.isTypeGroup('course')) return target; + + if (model.isTypeGroup('contentobject')) { + const descendants = Adapt.course.getAllDescendantModels(true).filter(i => i.isTypeGroup('contentobject')); + const precedingModels = descendants.slice(0, descendants.indexOf(model)); + const isPrecededByLockedContent = precedingModels.some(i => i.get('_isLocked')); + + if (isPrecededByLockedContent || model.get('_isLocked')) { + // do not allow navigation to a locked page/menu + const nearestUnlockedIndex = precedingModels.reverse().findIndex(i => !i.get('_isLocked')); + target = precedingModels[nearestUnlockedIndex].get('_id'); + } + + } else { + // bookmark is article/block/component + const descendants = model.findAncestor('pages').getAllDescendantModels(true); + const precedingModels = descendants.slice(0, descendants.indexOf(model)); + const isPrecededByLockedContent = precedingModels.some(i => i.get('_isLocked')); + + if (isPrecededByLockedContent) { + const nearestUnlockedIndex = precedingModels.reverse().findIndex(i => !i.get('_isLocked')); + target = precedingModels[nearestUnlockedIndex + 1].get('_id'); + } + } + + return target; + } + navigateTo(location = this.location) { const id = this.getLocationId(location); if (['', undefined, 'current'].includes(id)) return; _.defer(async () => { try { + const target = this.getAppropriateReturnPath(id); + const isSinglePage = (Adapt.contentObjects.models.length === 1); - await router.navigateToElement(id, { trigger: true, replace: isSinglePage, duration: 400 }); + await router.navigateToElement(target, { trigger: true, replace: isSinglePage, duration: 400 }); } catch (err) { logging.warn(`Bookmarking cannot navigate to id: ${id}\n`, err); } From fdb41e12eff8931258532147dd268d876ad3136c Mon Sep 17 00:00:00 2001 From: Chris Steele Date: Wed, 19 Jun 2024 14:23:54 +0100 Subject: [PATCH 2/6] Incorporating amendments from feedback Co-authored-by: Oliver Foster --- js/adapt-contrib-bookmarking.js | 49 ++++++++++++++------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/js/adapt-contrib-bookmarking.js b/js/adapt-contrib-bookmarking.js index 96975bd..769630c 100644 --- a/js/adapt-contrib-bookmarking.js +++ b/js/adapt-contrib-bookmarking.js @@ -176,36 +176,29 @@ class Bookmarking extends Backbone.Controller { * @param {string} id the bookmarked location * @returns the identifier of the location to return the user */ - getAppropriateReturnPath(id) { + resolveLocking(id) { const model = data.findById(id); - let target = id; - if (model.isTypeGroup('course')) return target; - - if (model.isTypeGroup('contentobject')) { - const descendants = Adapt.course.getAllDescendantModels(true).filter(i => i.isTypeGroup('contentobject')); - const precedingModels = descendants.slice(0, descendants.indexOf(model)); - const isPrecededByLockedContent = precedingModels.some(i => i.get('_isLocked')); - - if (isPrecededByLockedContent || model.get('_isLocked')) { - // do not allow navigation to a locked page/menu - const nearestUnlockedIndex = precedingModels.reverse().findIndex(i => !i.get('_isLocked')); - target = precedingModels[nearestUnlockedIndex].get('_id'); - } - - } else { - // bookmark is article/block/component - const descendants = model.findAncestor('pages').getAllDescendantModels(true); - const precedingModels = descendants.slice(0, descendants.indexOf(model)); - const isPrecededByLockedContent = precedingModels.some(i => i.get('_isLocked')); - - if (isPrecededByLockedContent) { - const nearestUnlockedIndex = precedingModels.reverse().findIndex(i => !i.get('_isLocked')); - target = precedingModels[nearestUnlockedIndex + 1].get('_id'); - } - } - - return target; + const isCourse = model.isTypeGroup('course'); + if (isCourse) return id; + + const isContentObject = model.isTypeGroup('contentobject'); + // do not allow navigation to a locked page/menu + const isLockedContentObject = isContentObject && model.get('_isLocked') + + // bookmark is by contentobject or article/block/component + const descendants = isContentObject + ? Adapt.course.getAllDescendantModels(true).filter(descendant => descendant.isTypeGroup('contentobject')) + : model.findAncestor('page').getAllDescendantModels(true); + + const precedingModels = descendants.slice(0, descendants.indexOf(model)); + const isPrecededByLockedContent = precedingModels.some(precedingModel => precedingModel.get('_isLocked')); + + if (!isPrecededByLockedContent && !isLockedContentObject) return id; + + const offset = isContentObject ? 0 : 1; + const nearestUnlockedIndex = precedingModels.reverse().findIndex(precedingModel => !precedingModel.get('_isLocked')); + return precedingModels[nearestUnlockedIndex + offset].get('_id'); } navigateTo(location = this.location) { From eee791e071c28c7535f868a4089f4702a7f76ef1 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 19 Jun 2024 15:32:22 +0100 Subject: [PATCH 3/6] Update js/adapt-contrib-bookmarking.js --- js/adapt-contrib-bookmarking.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/adapt-contrib-bookmarking.js b/js/adapt-contrib-bookmarking.js index 769630c..146fa96 100644 --- a/js/adapt-contrib-bookmarking.js +++ b/js/adapt-contrib-bookmarking.js @@ -206,7 +206,7 @@ class Bookmarking extends Backbone.Controller { if (['', undefined, 'current'].includes(id)) return; _.defer(async () => { try { - const target = this.getAppropriateReturnPath(id); + const target = this.resolveLocking(id); const isSinglePage = (Adapt.contentObjects.models.length === 1); await router.navigateToElement(target, { trigger: true, replace: isSinglePage, duration: 400 }); From 238ab48a94e6b552283588810e5b64f351af3142 Mon Sep 17 00:00:00 2001 From: Chris Steele Date: Wed, 19 Jun 2024 15:51:58 +0100 Subject: [PATCH 4/6] Removed offset as unnecessary --- js/adapt-contrib-bookmarking.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/js/adapt-contrib-bookmarking.js b/js/adapt-contrib-bookmarking.js index 146fa96..8af4bea 100644 --- a/js/adapt-contrib-bookmarking.js +++ b/js/adapt-contrib-bookmarking.js @@ -196,9 +196,8 @@ class Bookmarking extends Backbone.Controller { if (!isPrecededByLockedContent && !isLockedContentObject) return id; - const offset = isContentObject ? 0 : 1; const nearestUnlockedIndex = precedingModels.reverse().findIndex(precedingModel => !precedingModel.get('_isLocked')); - return precedingModels[nearestUnlockedIndex + offset].get('_id'); + return precedingModels[nearestUnlockedIndex].get('_id'); } navigateTo(location = this.location) { From 79bbe451fd8c94df0819f2739584f910b4c55956 Mon Sep 17 00:00:00 2001 From: Chris Steele Date: Wed, 19 Jun 2024 16:34:18 +0100 Subject: [PATCH 5/6] Amendments from feedback --- js/adapt-contrib-bookmarking.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/js/adapt-contrib-bookmarking.js b/js/adapt-contrib-bookmarking.js index 8af4bea..c15db09 100644 --- a/js/adapt-contrib-bookmarking.js +++ b/js/adapt-contrib-bookmarking.js @@ -184,33 +184,33 @@ class Bookmarking extends Backbone.Controller { const isContentObject = model.isTypeGroup('contentobject'); // do not allow navigation to a locked page/menu - const isLockedContentObject = isContentObject && model.get('_isLocked') + const isLockedContentObject = isContentObject && model.get('_isLocked'); // bookmark is by contentobject or article/block/component const descendants = isContentObject ? Adapt.course.getAllDescendantModels(true).filter(descendant => descendant.isTypeGroup('contentobject')) : model.findAncestor('page').getAllDescendantModels(true); - + const precedingModels = descendants.slice(0, descendants.indexOf(model)); const isPrecededByLockedContent = precedingModels.some(precedingModel => precedingModel.get('_isLocked')); - + if (!isPrecededByLockedContent && !isLockedContentObject) return id; const nearestUnlockedIndex = precedingModels.reverse().findIndex(precedingModel => !precedingModel.get('_isLocked')); - return precedingModels[nearestUnlockedIndex].get('_id'); + return precedingModels[nearestUnlockedIndex]?.get('_id'); } navigateTo(location = this.location) { const id = this.getLocationId(location); - if (['', undefined, 'current'].includes(id)) return; + const target = this.resolveLocking(id); + if (['', undefined, 'current'].includes(target)) return; _.defer(async () => { try { - const target = this.resolveLocking(id); const isSinglePage = (Adapt.contentObjects.models.length === 1); await router.navigateToElement(target, { trigger: true, replace: isSinglePage, duration: 400 }); } catch (err) { - logging.warn(`Bookmarking cannot navigate to id: ${id}\n`, err); + logging.warn(`Bookmarking cannot navigate to id: ${target}\n`, err); } }); this.stopListening(Adapt, 'bookmarking:cancel'); From ac01c9349b960c91ce2d4f8b6dba0543a9762df2 Mon Sep 17 00:00:00 2001 From: Chris Steele Date: Wed, 19 Jun 2024 16:50:07 +0100 Subject: [PATCH 6/6] Update js/adapt-contrib-bookmarking.js Co-authored-by: Oliver Foster --- js/adapt-contrib-bookmarking.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/adapt-contrib-bookmarking.js b/js/adapt-contrib-bookmarking.js index c15db09..a6bdb89 100644 --- a/js/adapt-contrib-bookmarking.js +++ b/js/adapt-contrib-bookmarking.js @@ -202,8 +202,9 @@ class Bookmarking extends Backbone.Controller { navigateTo(location = this.location) { const id = this.getLocationId(location); + if (['', undefined, 'current'].includes(id)) return; const target = this.resolveLocking(id); - if (['', undefined, 'current'].includes(target)) return; + if (!target) return; _.defer(async () => { try {