UNPKG

@oat-sa/tao-test-runner-qti

Version:
178 lines (161 loc) 6.66 kB
define(function () { 'use strict'; /** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; under version 2 * of the License (non-upgradable). * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2016 (original work) Open Assessment Technologies SA ; */ /** * This is a helper for navigation plugins. It decides if a warning should be displayed * before actually moving to the next item * * @author Christophe Noël <christophe@taotesting.com> */ /** * Convert a value to a boolean * @param {*} value * @param {Boolean} defaultValue * @returns {Boolean} */ var toBoolean = function toBoolean(value, defaultValue) { if (typeof value === 'undefined') { return defaultValue; } else { return value === true || value === 'true'; } }; /** * @param {Object} options * @param {Boolean} options.endTestWarning - enables the end test warning, when applicable * @param {Boolean} options.isLast - if the item is the last of the test * @param {Boolean} options.isLinear - if the current part is linear * @param {Boolean} options.nextItemWarning - enables the next item warning, when applicable * @param {Boolean} options.nextPartWarning - enables the next item warning on part change * @param {Boolean} options.stats - current state of the test * @param {Object} options.nextPart - description of the next part of the test * @param {Number} options.remainingAttempts - remaining attempts for the current item * @param {String} options.testPartId - current test part identifier * @param {Boolean} options.unansweredOnly - warn only if there are unanswered/flagged items * @returns {Object} */ var nextWarningHelper = function nextWarningHelper(options) { var endTestWarning = toBoolean(options.endTestWarning, false), isLast = toBoolean(options.isLast, false), isLinear = toBoolean(options.isLinear, false), nextItemWarning = toBoolean(options.nextItemWarning, false), nextPartWarning = toBoolean(options.nextPartWarning, false), stats = options.stats, nextPart = options.nextPart || {}, remainingAttempts = typeof options.remainingAttempts === 'undefined' ? -1 : options.remainingAttempts, testPartId = options.testPartId || '', unansweredOnly = toBoolean(options.unansweredOnly, false), warnBeforeNext = shouldWarnBeforeNext(), warnBeforeEnd = shouldWarnBeforeEnd(), warnBeforeEndPart = shouldWarnBeforeEndPart(); /** * Decide if we should display a warning before moving to the next item. * This is useful to prevent accidental navigation (for example by pressing a shortcut) that would occur * before the test taker actually gets a chance to answer an item */ function shouldWarnBeforeNext() { return nextItemWarning && !itemCanBeTriedAtWill(); //&& !exitTimedSectionWarning(); //todo: this should be implemented to prevent a double warning! } /** * We try to decide if the test taker has the freedom to come back to this item as many times as he wants */ function itemCanBeTriedAtWill() { return isLast === false && // the test is not over isLinear === false && // the context is not linear remainingAttempts === -1 && // the item doesn't have a configured max attempts number !isNextItemInLinearPart() // the next item is not in a linear part ; } /** * Check if the next item is in a linear part, as this would prevent the test taker to come back to the current item */ function isNextItemInLinearPart() { return nextPart && typeof nextPart.isLinear !== 'undefined' && isLastOfPart() && nextPart.isLinear === true; } /** * Decide if we should display a warning before ending the test */ function shouldWarnBeforeEnd() { return shouldWarnOnTestEnd(); } /** * Decide if we should display a warning before ending the test part */ function shouldWarnBeforeEndPart() { return shouldWarnOnPartChange(); } /** * Are we on the last test item? * @returns {Boolean} */ function shouldWarnOnTestEnd() { return isLast && (endTestWarning || // warning is explicitly required by endTestWarning category warnBeforeNext) && // warning is implicitly triggered by the next item warning being true (prevent double warning) shouldWarnForUnansweredItems(); } /** * Provide the opportunity to cancel the display of the warning if there are no unanswered/flagged item * for this to work, the unansweredOnly option has to be set * @returns {Boolean} */ function shouldWarnForUnansweredItems() { var hasUnanswered = stats && stats.questions - stats.answered !== 0, hasFlagged = stats && stats.flagged !== 0; if (unansweredOnly) { return hasUnanswered || hasFlagged; } else { return true; } } /** * Are we on the last part item? * @returns {Boolean} */ function shouldWarnOnPartChange() { return nextPartWarning && isLastOfPart() && shouldWarnForUnansweredItems(); } /** * Check if the next item belong to a different part * @returns {Boolean} */ function isLastOfPart() { return nextPart && nextPart.id && testPartId !== nextPart.id; } /** * The helper object */ return { shouldWarnBeforeEndPart: function () { return warnBeforeEndPart; }, shouldWarnBeforeEnd: function () { return warnBeforeEnd; }, shouldWarnBeforeNext: function () { return warnBeforeNext; } }; }; return nextWarningHelper; });