263 lines
10 KiB
JavaScript
263 lines
10 KiB
JavaScript
/**
|
|
* 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) 2014-2019 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
|
|
*/
|
|
/**
|
|
* @author Bertrand Chevrier <bertrand@taotesting.com>
|
|
*/
|
|
define([
|
|
'module',
|
|
'jquery',
|
|
'lodash',
|
|
'helpers',
|
|
'i18n',
|
|
'ui/feedback',
|
|
'core/databindcontroller',
|
|
'taoQtiTest/controller/creator/qtiTestCreator',
|
|
'taoQtiTest/controller/creator/views/item',
|
|
'taoQtiTest/controller/creator/views/test',
|
|
'taoQtiTest/controller/creator/views/testpart',
|
|
'taoQtiTest/controller/creator/views/section',
|
|
'taoQtiTest/controller/creator/views/itemref',
|
|
'taoQtiTest/controller/creator/encoders/dom2qti',
|
|
'taoQtiTest/controller/creator/templates/index',
|
|
'taoQtiTest/controller/creator/helpers/qtiTest',
|
|
'taoQtiTest/controller/creator/helpers/scoring',
|
|
'taoQtiTest/controller/creator/helpers/categorySelector',
|
|
'ui/validator/validators',
|
|
'taoQtiTest/controller/creator/helpers/changeTracker',
|
|
'taoTests/previewer/factory',
|
|
'core/logger'
|
|
], function(
|
|
module,
|
|
$,
|
|
_,
|
|
helpers,
|
|
__,
|
|
feedback,
|
|
DataBindController,
|
|
qtiTestCreatorFactory,
|
|
itemView,
|
|
testView,
|
|
testPartView,
|
|
sectionView,
|
|
itemrefView,
|
|
Dom2QtiEncoder,
|
|
templates,
|
|
qtiTestHelper,
|
|
scoringHelper,
|
|
categorySelector,
|
|
validators,
|
|
changeTracker,
|
|
previewerFactory,
|
|
loggerFactory
|
|
){
|
|
'use strict';
|
|
const logger = loggerFactory('taoQtiTest/controller/creator');
|
|
|
|
/**
|
|
* The test creator controller is the main entry point
|
|
* and orchestrates data retrieval and view/components loading.
|
|
* @exports creator/controller
|
|
*/
|
|
const Controller = {
|
|
|
|
routes : {},
|
|
|
|
/**
|
|
* Start the controller, main entry method.
|
|
* @public
|
|
* @param {Object} options
|
|
* @param {Object} options.labels - the list of item's labels to give to the ItemView
|
|
* @param {Object} options.routes - action's urls
|
|
* @param {Object} options.categoriesPresets - predefined category that can be set at the item or section level
|
|
* @param {Boolean} [options.guidedNavigation=false] - feature flag for the guided navigation
|
|
*/
|
|
start(options) {
|
|
const $container = $('#test-creator');
|
|
const $saver = $('#saver');
|
|
const $previewer = $('#previewer');
|
|
const $back = $('#authoringBack');
|
|
|
|
let creatorContext;
|
|
let binder;
|
|
let binderOptions;
|
|
let modelOverseer;
|
|
|
|
this.identifiers = [];
|
|
|
|
options = _.merge(module.config(), options || {});
|
|
options.routes = options.routes || {};
|
|
options.labels = options.labels || {};
|
|
options.categoriesPresets = options.categoriesPresets || {};
|
|
options.guidedNavigation = options.guidedNavigation === true;
|
|
|
|
categorySelector.setPresets(options.categoriesPresets);
|
|
|
|
//back button
|
|
$back.on('click', e => {
|
|
e.preventDefault();
|
|
if (creatorContext) {
|
|
creatorContext.trigger('creatorclose');
|
|
}
|
|
});
|
|
|
|
//preview button
|
|
if (!Object.keys(options.labels).length) {
|
|
$previewer.attr('disabled', true).addClass('disabled');
|
|
}
|
|
$previewer.on('click', e => {
|
|
e.preventDefault();
|
|
if(!$previewer.hasClass('disabled')) {
|
|
creatorContext.trigger('preview');
|
|
}
|
|
});
|
|
const isTestContainsItems = () => {
|
|
if ($container.find('.test-content').find('.itemref').length) {
|
|
$previewer.attr('disabled', false).removeClass('disabled');
|
|
return true;
|
|
} else {
|
|
$previewer.attr('disabled', true).addClass('disabled');
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//set up the ItemView, give it a configured loadItems ref
|
|
itemView($('.test-creator-items .item-selection', $container));
|
|
|
|
// forwards some binder events to the model overseer
|
|
$container.on('change.binder delete.binder', (e, model) => {
|
|
if (e.namespace === 'binder' && model && modelOverseer) {
|
|
modelOverseer.trigger(e.type, model);
|
|
}
|
|
});
|
|
|
|
//Data Binding options
|
|
binderOptions = _.merge(options.routes, {
|
|
filters : {
|
|
isItemRef : value => qtiTestHelper.filterQtiType(value, 'assessmentItemRef'),
|
|
isSection : value => qtiTestHelper.filterQtiType(value, 'assessmentSection')
|
|
},
|
|
encoders : {
|
|
'dom2qti' : Dom2QtiEncoder
|
|
},
|
|
templates : templates,
|
|
beforeSave(model) {
|
|
//ensure the qti-type is present
|
|
qtiTestHelper.addMissingQtiType(model);
|
|
|
|
//apply consolidation rules
|
|
qtiTestHelper.consolidateModel(model);
|
|
|
|
//validate the model
|
|
try {
|
|
qtiTestHelper.validateModel(model);
|
|
} catch(err) {
|
|
$saver.attr('disabled', false).removeClass('disabled');
|
|
feedback().error(`${__('The test has not been saved.')} + ${err}`);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
|
|
//set up the databinder
|
|
binder = DataBindController
|
|
.takeControl($container, binderOptions)
|
|
.get( model => {
|
|
|
|
creatorContext = qtiTestCreatorFactory($container, {
|
|
uri : options.uri,
|
|
labels : options.labels,
|
|
routes : options.routes,
|
|
guidedNavigation : options.guidedNavigation
|
|
});
|
|
creatorContext.setTestModel(model);
|
|
modelOverseer = creatorContext.getModelOverseer();
|
|
|
|
//detect the scoring mode
|
|
scoringHelper.init(modelOverseer);
|
|
|
|
//register validators
|
|
validators.register('idFormat', qtiTestHelper.idFormatValidator());
|
|
validators.register('testIdFormat', qtiTestHelper.testidFormatValidator());
|
|
validators.register('testIdAvailable', qtiTestHelper.idAvailableValidator(modelOverseer), true);
|
|
|
|
//once model is loaded, we set up the test view
|
|
testView(creatorContext);
|
|
|
|
//listen for changes to update available actions
|
|
testPartView.listenActionState();
|
|
sectionView.listenActionState();
|
|
itemrefView.listenActionState();
|
|
itemrefView.resize();
|
|
|
|
$(window)
|
|
.off('resize.qti-test-creator')
|
|
.on('resize.qti-test-creator', () => itemrefView.resize() );
|
|
|
|
changeTracker($container.get()[0], creatorContext, '.content-wrap');
|
|
|
|
creatorContext.on('save', function() {
|
|
if(!$saver.hasClass('disabled')){
|
|
$saver.prop('disabled', true).addClass('disabled');
|
|
binder.save(function() {
|
|
$saver.prop('disabled', false).removeClass('disabled');
|
|
feedback().success(__('Test Saved'));
|
|
isTestContainsItems();
|
|
creatorContext.trigger('saved');
|
|
}, function() {
|
|
$saver.prop('disabled', false).removeClass('disabled');
|
|
});
|
|
}
|
|
});
|
|
|
|
creatorContext.on('preview', function() {
|
|
if(isTestContainsItems()) {
|
|
const saveUrl = options.routes.save;
|
|
const testUri = saveUrl.slice(saveUrl.indexOf('uri=') + 4);
|
|
return previewerFactory(
|
|
module.config().provider,
|
|
decodeURIComponent(testUri),
|
|
{
|
|
readOnly: false,
|
|
fullPage: true
|
|
}
|
|
)
|
|
.catch(err => {
|
|
logger.error(err);
|
|
feedback().error(__('Test Preview is not installed, please contact to your administrator.'));
|
|
});
|
|
}
|
|
});
|
|
|
|
creatorContext.on('creatorclose', () => {
|
|
creatorContext.trigger('exit');
|
|
window.history.back();
|
|
});
|
|
});
|
|
|
|
//the save button triggers binder's save action.
|
|
$saver.on('click', function(event){
|
|
event.preventDefault();
|
|
creatorContext.trigger('save');
|
|
});
|
|
}
|
|
};
|
|
|
|
return Controller;
|
|
});
|