Skip to content
Open
Show file tree
Hide file tree
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
18 changes: 9 additions & 9 deletions js/TrickleButtonModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,18 @@ export default class TrickleButtonModel extends ComponentModel {
const text = (isDisabled && trickleConfig._button.disabledText) ?
trickleConfig._button.disabledText :
(isStart && trickleConfig._button.startText) ?
trickleConfig._button.startText :
(isFinal && trickleConfig._button.finalText) ?
trickleConfig._button.finalText :
trickleConfig._button.text;
trickleConfig._button.startText :
(isFinal && trickleConfig._button.finalText) ?
trickleConfig._button.finalText :
trickleConfig._button.text;

const ariaLabel = (isDisabled && trickleConfig._button.disabledAriaLabel) ?
trickleConfig._button.disabledAriaLabel :
trickleConfig._button.disabledAriaLabel :
(isStart && trickleConfig._button.startAriaLabel) ?
trickleConfig._button.startAriaLabel :
(isFinal && trickleConfig._button.finalAriaLabel) ?
trickleConfig._button.finalAriaLabel :
trickleConfig._button.ariaLabel;
trickleConfig._button.startAriaLabel :
(isFinal && trickleConfig._button.finalAriaLabel) ?
trickleConfig._button.finalAriaLabel :
trickleConfig._button.ariaLabel;

this.set({
buttonText: text,
Expand Down
31 changes: 28 additions & 3 deletions js/TrickleButtonView.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Adapt from 'core/js/adapt';
import a11y from 'core/js/a11y';
import notify from 'core/js/notify';
import ComponentView from 'core/js/views/componentView';
import controller from './controller';
import {
getModelConfig,
getCompletionAttribute
} from './models';
import wait from 'core/js/wait';

/** @typedef {import('core/js/modelEvent').default} ModelEvent */

Expand Down Expand Up @@ -72,7 +74,7 @@ class TrickleButtonView extends ComponentView {
this.$el.on('onscreen', this.tryButtonAutoHide);
this.listenTo(Adapt, {
'popup:opened': this.onPopupOpened,
'popup:closed': this.onPopupClosed
'popup:closing': this.onPopupClosed
});
const parentModel = this.model.getParent();
const completionAttribute = getCompletionAttribute(parentModel);
Expand Down Expand Up @@ -100,6 +102,8 @@ class TrickleButtonView extends ComponentView {
this.openPopupCount--;
if (this.openPopupCount) return;
if (this.isAwaitingPopupClose) {
this._isWaiting = true;
wait.begin();
// Had completed with an open popup, perform final part of finishing
return this.finish();
}
Expand Down Expand Up @@ -187,7 +191,7 @@ class TrickleButtonView extends ComponentView {
async finish() {
this.stopListening(Adapt, {
'popup:opened': this.onPopupOpened,
'popup:closed': this.onPopupClosed
'popup:closing': this.onPopupClosed
});
this.updateButtonState();
const isStepLockingCompletionRequired = this.model.isStepLockingCompletionRequired();
Expand All @@ -202,10 +206,31 @@ class TrickleButtonView extends ComponentView {
*/
async continue() {
const parent = this.model.getParent();
await controller.continue();
// Announce "Loading" concurrent with the load so the message plays during
// the load wait rather than after content is ready (which would race with
// the focus shift to the next component).
const announcePromise = this.announceContentLoaded();
const childrenAdded = await controller.continue();
await announcePromise;
if (this._isWaiting) {
this._isWaiting = false;
a11y.setPopupCloseTo(childrenAdded[0]?.$el);
wait.end();
}
await controller.scroll(parent);
}

/**
* Announce a message to screenreaders letting them know that additional
* content has been loaded on the page.
*/
async announceContentLoaded() {
const globals = Adapt.course.get('_globals');
const message = globals?._extensions?._trickle?.additionalContentLoaded;
if (!message) return;
await notify.read(message);
}

tryButtonAutoHide() {
if (!this.model.get('_isButtonVisible')) return;
const trickleConfig = getModelConfig(this.model.getParent());
Expand Down
9 changes: 6 additions & 3 deletions js/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,11 @@ class TrickleController extends Backbone.Controller {
*/
async continue() {
applyLocks();
await Adapt.parentView.addChildren();
const addedChildren = await Adapt.parentView.addChildren({
returnNewDescendants: true
});
await Adapt.parentView.whenReady();
return addedChildren;
}

/**
Expand Down Expand Up @@ -160,8 +163,8 @@ class TrickleController extends Backbone.Controller {

let scrollToId = getScrollToId();
if (!scrollToId) {
logging.error(`Cannot scroll to the next id as none was found at id: "${fromModel.get('_id')}" with _scrollTo: "${trickleConfig._scrollTo}". Suggestion: Set _showEndOfPage to false.`)
return
logging.error(`Cannot scroll to the next id as none was found at id: "${fromModel.get('_id')}" with _scrollTo: "${trickleConfig._scrollTo}". Suggestion: Set _showEndOfPage to false.`);
return;
}

const isDescendant = Adapt.parentView.model.getAllDescendantModels().some(model => {
Expand Down
53 changes: 52 additions & 1 deletion migrations/v7.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, whereContent, whereFromPlugin, mutateContent, checkContent, updatePlugin, testStopWhere, testSuccessWhere, getConfig } from 'adapt-migrations';
import { describe, whereContent, whereFromPlugin, mutateContent, checkContent, updatePlugin, testStopWhere, testSuccessWhere, getConfig, getCourse } from 'adapt-migrations';
import _ from 'lodash';

describe('Trickle - v7.1.3 to v7.2.0', async () => {
Expand Down Expand Up @@ -145,3 +145,54 @@ describe('Trickle - v7.5.0 to v7.5.1', async () => {
fromPlugins: [{ name: 'adapt-contrib-trickle', version: '7.5.1' }]
});
});

describe('Trickle - @@CURRENT_VERSION to @@RELEASE_VERSION', async () => {
// https://github.com/adaptlearning/adapt-contrib-trickle/compare/@@CURRENT_VERSION..@@RELEASE_VERSION

let course, courseTrickleGlobals;
const additionalContentLoaded = 'Loading.';

whereFromPlugin('Trickle - from @@CURRENT_VERSION', { name: 'adapt-contrib-trickle', version: '<@@RELEASE_VERSION' });

whereContent('Trickle - where course is present', async (content) => {
course = getCourse();
return course;
});

mutateContent('Trickle - add globals if missing', async (content) => {
if (!_.has(course, '_globals._extensions._trickle')) _.set(course, '_globals._extensions._trickle', {});
courseTrickleGlobals = course._globals._extensions._trickle;
return true;
});

mutateContent('Trickle - add global attribute additionalContentLoaded', async (content) => {
if (!_.has(courseTrickleGlobals, 'additionalContentLoaded')) courseTrickleGlobals.additionalContentLoaded = additionalContentLoaded;
return true;
});

checkContent('Trickle - check global attribute additionalContentLoaded', async (content) => {
const isValid = _.has(courseTrickleGlobals, 'additionalContentLoaded');
if (!isValid) throw new Error('Trickle - global attribute additionalContentLoaded');
return true;
});

updatePlugin('Trickle - update to @@RELEASE_VERSION', { name: 'adapt-contrib-trickle', version: '@@RELEASE_VERSION', framework: '>=5.46.4' });

testSuccessWhere('trickle with course, no globals', {
fromPlugins: [{ name: 'adapt-contrib-trickle', version: '@@CURRENT_VERSION' }],
content: [
{ _type: 'course' }
]
});

testSuccessWhere('trickle with course, with other globals', {
fromPlugins: [{ name: 'adapt-contrib-trickle', version: '@@CURRENT_VERSION' }],
content: [
{ _type: 'course', _globals: { _extensions: { _trickle: {} } } }
]
});

testStopWhere('trickle incorrect version', {
fromPlugins: [{ name: 'adapt-contrib-trickle', version: '@@RELEASE_VERSION' }]
});
});
10 changes: 10 additions & 0 deletions properties.schema
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@
"inputType": "Text",
"validators": [],
"translatable": true
},
"additionalContentLoaded": {
"type": "string",
"required": true,
"title": "Additional content loaded.",
"default": "Loading.",
"inputType": "Text",
"help": "Announced to screen readers when additional content is loaded. Recommend keeping this short.",
"validators": [],
"translatable": true
}
},
"properties": {
Expand Down
9 changes: 9 additions & 0 deletions schema/course.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@
"_adapt": {
"translatable": true
}
},
"additionalContentLoaded": {
"type": "string",
"title": "Additional content loaded",
"default": "Loading.",
"description": "Announced to screen readers when additional content is loaded. Recommend keeping this short.",
"_adapt": {
"translatable": true
}
}
}
}
Expand Down