@oat-sa/tao-test-runner-qti
Version:
TAO Test Runner QTI implementation
235 lines (219 loc) • 8.53 kB
JavaScript
define(['lodash', 'i18n', 'taoTests/runner/plugin', 'ui/hider', 'util/shortcut', 'util/namespace', 'taoQtiTest/runner/helpers/map', 'taoQtiTest/runner/plugins/tools/lineReader/compoundMask'], function (_, __, pluginFactory, hider, shortcut, namespaceHelper, mapHelper, compoundMaskFactory) { 'use strict';
_ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
__ = __ && Object.prototype.hasOwnProperty.call(__, 'default') ? __['default'] : __;
pluginFactory = pluginFactory && Object.prototype.hasOwnProperty.call(pluginFactory, 'default') ? pluginFactory['default'] : pluginFactory;
shortcut = shortcut && Object.prototype.hasOwnProperty.call(shortcut, 'default') ? shortcut['default'] : shortcut;
namespaceHelper = namespaceHelper && Object.prototype.hasOwnProperty.call(namespaceHelper, 'default') ? namespaceHelper['default'] : namespaceHelper;
mapHelper = mapHelper && Object.prototype.hasOwnProperty.call(mapHelper, 'default') ? mapHelper['default'] : mapHelper;
compoundMaskFactory = compoundMaskFactory && Object.prototype.hasOwnProperty.call(compoundMaskFactory, 'default') ? compoundMaskFactory['default'] : compoundMaskFactory;
/**
* 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 ;
*/
/**
* The public name of the plugin
* @type {String}
*/
var pluginName = 'line-reader';
/**
* The prefix of actions triggered through the event loop
* @type {String}
*/
var actionPrefix = `tool-${pluginName}-`;
/**
* Options for the compoundMask factory
* @type {Object}
*/
var maskOptions = {
dragMinWidth: 17,
dragMinHeight: 7,
resizeHandleSize: 7,
innerDragHeight: 20
};
var dimensions, position;
/**
* These functions are a first effort to place the mask on the first line on the item
* They make a lot of assumptions:
* - the item starts with a text
* - the padding is set on the .qti-item container
* - the padding is consistent with the minWidth/minHeight configuration of the mask
* - and some other...
* @param {jQuery} $container - where the mask is appended
*/
function getDimensions($container) {
var $qtiContent = $container.find('#qti-content'),
$qtiItem = $qtiContent.find('.qti-item'),
lineHeight = Math.ceil(parseFloat($qtiContent.css('line-height'))) || 20; // reasonable default line height
return {
outerWidth: $qtiItem.width() + maskOptions.resizeHandleSize * 4 + maskOptions.dragMinWidth * 2,
outerHeight: 175,
// reasonable default height
innerWidth: $qtiItem.width(),
innerHeight: lineHeight
};
}
function getPosition($container) {
var $qtiContent = $container.find('#qti-content'),
$qtiItem = $qtiContent.find('.qti-item'),
itemPosition = $qtiItem.position() || {},
paddingLeft = parseInt($qtiItem.css('padding-left'), 10),
paddingTop = parseInt($qtiItem.css('padding-top'), 10),
textPadding = 3,
// this is to let the text breathe a bit
innerX = parseInt(itemPosition.left, 10) + paddingLeft - textPadding,
innerY = parseInt(itemPosition.top, 10) + paddingTop - textPadding;
return {
outerX: innerX - maskOptions.resizeHandleSize * 2 - maskOptions.dragMinWidth,
outerY: 0,
innerX: innerX,
innerY: innerY
};
}
function containerWidthHasChanged($container) {
var newDimensions = getDimensions($container);
return newDimensions.outerWidth !== dimensions.outerWidth;
}
/**
* Returns the configured plugin
*/
var plugin = pluginFactory({
name: pluginName,
/**
* Initialize the plugin (called during runner's init)
*/
init: function init() {
const self = this;
const testRunner = this.getTestRunner();
const testRunnerOptions = testRunner.getOptions();
const pluginShortcuts = (testRunnerOptions.shortcuts || {})[pluginName] || {};
const $container = testRunner.getAreaBroker().getContentArea().parent();
this.compoundMask = compoundMaskFactory(maskOptions).init().render($container).on('close', function () {
closeMask();
}).hide();
/**
* Checks if the plugin is currently available
* @returns {Boolean}
*/
function isEnabled() {
//to be activated with the special category x-tao-option-lineReader
return mapHelper.hasItemCategory(testRunner.getTestMap(), testRunner.getTestContext().itemIdentifier, 'lineReader', true);
}
function toggleButton() {
if (isEnabled()) {
self.show();
} else {
self.hide();
}
}
function toggleMask() {
if (self.compoundMask.getState('hidden')) {
if (containerWidthHasChanged($container)) {
transformMask($container);
}
openMask();
} else {
closeMask();
}
}
function openMask() {
self.compoundMask.show();
self.trigger('start');
self.button.turnOn();
}
function closeMask() {
if (!self.compoundMask.getState('hidden')) {
self.compoundMask.hide();
}
self.trigger('end');
self.button.turnOff();
}
function transformMask($maskContainer) {
dimensions = getDimensions($maskContainer);
position = getPosition($maskContainer);
self.compoundMask.setTransforms(_.clone(dimensions), _.clone(position));
}
// create button
this.button = this.getAreaBroker().getToolbox().createEntry({
title: __('Line Reader'),
icon: 'insert-horizontal-line',
control: 'line-reader',
text: __('Line Reader')
});
// attach user events
this.button.on('click', function (e) {
e.preventDefault();
testRunner.trigger(`${actionPrefix}toggle`);
});
if (testRunnerOptions.allowShortcuts) {
if (pluginShortcuts.toggle) {
shortcut.add(namespaceHelper.namespaceAll(pluginShortcuts.toggle, this.getName(), true), function () {
testRunner.trigger(`${actionPrefix}toggle`);
}, {
avoidInput: true,
prevent: true
});
}
}
//start disabled
this.disable();
//update plugin state based on changes
testRunner.on('loaditem', toggleButton).on('renderitem', function () {
transformMask($container);
}).on('enabletools renderitem', function () {
self.enable();
}).on('disabletools unloaditem', function () {
self.disable();
closeMask();
}).on(`${actionPrefix}toggle`, function () {
if (isEnabled()) {
toggleMask();
}
});
},
/**
* Called during the runner's destroy phase
*/
destroy: function destroy() {
this.compoundMask.destroy();
shortcut.remove(`.${this.getName()}`);
},
/**
* Enable the button
*/
enable: function enable() {
this.button.enable();
},
/**
* Disable the button
*/
disable: function disable() {
this.button.disable();
},
/**
* Show the button
*/
show: function show() {
this.button.show();
},
/**
* Hide the button
*/
hide: function hide() {
this.button.hide();
}
});
return plugin;
});