UNPKG

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

Version:
306 lines (289 loc) 11.5 kB
define(['lodash', 'i18n', 'ui/hider', 'util/shortcut', 'util/namespace', 'taoTests/runner/plugin', 'taoQtiTest/runner/helpers/map', 'ui/keyNavigation/navigator', 'ui/keyNavigation/navigableDomElement', 'taoQtiTest/runner/plugins/tools/apipTextToSpeech/textToSpeech', 'taoQtiTest/runner/plugins/tools/apipTextToSpeech/ttsApipDataProvider'], function (_, __, hider, shortcut, namespaceHelper, pluginFactory, mapHelper, keyNavigator, navigableDomElement, ttsComponentFactory, ttsApipDataProvider) { 'use strict'; _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _; __ = __ && Object.prototype.hasOwnProperty.call(__, 'default') ? __['default'] : __; shortcut = shortcut && Object.prototype.hasOwnProperty.call(shortcut, 'default') ? shortcut['default'] : shortcut; namespaceHelper = namespaceHelper && Object.prototype.hasOwnProperty.call(namespaceHelper, 'default') ? namespaceHelper['default'] : namespaceHelper; pluginFactory = pluginFactory && Object.prototype.hasOwnProperty.call(pluginFactory, 'default') ? pluginFactory['default'] : pluginFactory; mapHelper = mapHelper && Object.prototype.hasOwnProperty.call(mapHelper, 'default') ? mapHelper['default'] : mapHelper; keyNavigator = keyNavigator && Object.prototype.hasOwnProperty.call(keyNavigator, 'default') ? keyNavigator['default'] : keyNavigator; navigableDomElement = navigableDomElement && Object.prototype.hasOwnProperty.call(navigableDomElement, 'default') ? navigableDomElement['default'] : navigableDomElement; ttsComponentFactory = ttsComponentFactory && Object.prototype.hasOwnProperty.call(ttsComponentFactory, 'default') ? ttsComponentFactory['default'] : ttsComponentFactory; ttsApipDataProvider = ttsApipDataProvider && Object.prototype.hasOwnProperty.call(ttsApipDataProvider, 'default') ? ttsApipDataProvider['default'] : ttsApipDataProvider; /** * 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-2019 (original work) Open Assessment Technologies SA; * * @author Anton Tsymuk <anton@taotesting.com> */ const pluginName = 'apiptts'; const actionPrefix = `tool-${pluginName}-`; /** * Returns the configured plugin */ var plugin = pluginFactory({ name: pluginName, /** * Initialize the plugin (called during runner's init) */ init() { const testRunner = this.getTestRunner(); const testRunnerOptions = testRunner.getOptions(); const pluginShortcuts = (testRunnerOptions.shortcuts || {})[this.getName()] || {}; let ttsComponent; let ttsApipData; const createNavigationGroup = () => { const $container = testRunner.getAreaBroker().getContainer(); const $navigationGroupElement = this.button.getElement(); const groupNavigationId = `${pluginName}_navigation_group`; const $navigationElements = $container.find(ttsApipData.map(_ref => { let { selector } = _ref; return selector; }).join(', ')); this.navigationGroup = keyNavigator({ id: groupNavigationId, group: $navigationGroupElement, elements: navigableDomElement.createFromDoms($navigationElements.add($navigationGroupElement)), propagateTab: false, loop: true, keepState: true }).on('tab', () => { if (ttsComponent.is('sfhMode')) { this.navigationGroup.next(); testRunner.trigger(`${actionPrefix}next`); } }).on('shift+tab', () => { if (ttsComponent.is('sfhMode')) { this.navigationGroup.previous(); testRunner.trigger(`${actionPrefix}previous`); } }).on('activate', () => { if (ttsComponent.is('sfhMode')) { testRunner.trigger(`${actionPrefix}togglePlayback`); } }).on('blur', () => { setTimeout(() => { if (!this.navigationGroup.isFocused()) { this.navigationGroup.focus(); } }, 0); }).setCursorAt($navigationElements.length); ttsComponent.on('next finish', () => { if (ttsComponent.is('sfhMode')) { const $currentElement = this.navigationGroup.getCursor().navigable.getElement(); const { selector } = ttsComponent.getCurrentItem() || {}; if (!selector || !$currentElement.is(selector)) { this.navigationGroup.next(); } } }); }; /** * Creates the tts component on demand * @returns {textToSpeech} */ const getTTSComponent = () => { if (!ttsComponent) { const $container = testRunner.getAreaBroker().getContainer(); ttsComponent = ttsComponentFactory($container, {}).on('close', () => { if (this.getState('active')) { testRunner.trigger(`${actionPrefix}toggle`); } }).hide(); } return ttsComponent; }; /** * Checks if the plugin is currently available. * To be activated with the special category x-tao-option-apiptts * * @returns {Boolean} */ const isConfigured = () => mapHelper.hasItemCategory(testRunner.getTestMap(), testRunner.getTestContext().itemIdentifier, 'apiptts', true); /** * Is plugin activated ? if not, then we hide the plugin */ const togglePlugin = () => { if (isConfigured()) { this.show(); } else { this.hide(); } }; /** * Show the plugin panel * * @fires plugin-open.apiptts */ const enablePlugin = () => { createNavigationGroup(); this.button.turnOn(); this.setState('active', true); this.trigger('open'); if (ttsComponent.is('hidden')) { ttsComponent.show(); } }; /** * Hide the plugin panel * * @fires plugin-close.apiptts */ const disablePlugin = () => { if (this.getState('active')) { this.navigationGroup.blur(); this.navigationGroup.destroy(); this.setState('active', false); this.button.turnOff(); this.trigger('close'); if (ttsComponent && !ttsComponent.is('hidden')) { ttsComponent.close(); ttsComponent.hide(); } } }; /** * Shows/hides the plugin */ const toggleTool = () => { if (this.getState('enabled')) { if (this.getState('active')) { disablePlugin(); this.setState('sleep', true); } else { enablePlugin(); this.setState('sleep', false); } } }; // Add plugin button to toolbox this.button = this.getAreaBroker().getToolbox().createEntry({ className: `${this.getName()}-plugin`, control: this.getName(), icon: 'headphones', text: __('Text To Speech'), title: __('Enable text to speech') }); // Handle plugin button click this.button.on('click', e => { e.preventDefault(); testRunner.trigger(`${actionPrefix}toggle`); }); // Register plugin shortcuts if (testRunnerOptions.allowShortcuts) { _.forEach(pluginShortcuts, (command, key) => { shortcut.add(namespaceHelper.namespaceAll(command, pluginName, true), () => { if (key === 'spaceTogglePlayback' && ttsComponent && ttsComponent.is('sfhMode')) { return; } const eventKey = key.endsWith('TogglePlayback') ? 'togglePlayback' : key; testRunner.trigger(actionPrefix + eventKey); }, { avoidInput: true }); }); } // Hide plugin by default togglePlugin(); this.disable(); this.hide(); //update plugin state based on changes testRunner.on('loaditem', () => { togglePlugin(); this.disable(); }).on('enabletools renderitem', () => { this.enable(); }).on('disabletools unloaditem', () => { disablePlugin(); this.disable(); }).on(`${actionPrefix}toggle`, () => { if (isConfigured()) { toggleTool(); } }).on(`${actionPrefix}togglePlayback`, () => { if (this.getState('enabled')) { if (this.getState('active')) { if (ttsComponent.is('sfhMode')) { const $currentElement = this.navigationGroup.getCursor().navigable.getElement(); const { selector } = ttsComponent.getCurrentItem() || {}; if (!$currentElement.is(selector)) { if (this.button.getElement()[0] !== $currentElement[0]) { $currentElement.trigger('click'); } return; } } ttsComponent.togglePlayback(); } } }).on('renderitem', () => { if (!isConfigured()) { return; } ttsApipData = ttsApipDataProvider(testRunner.itemRunner.getData().apipAccessibility || {}).map(apipItemData => Object.assign({}, apipItemData, { url: testRunner.itemRunner.assetManager.resolve(apipItemData.url) })); if (!ttsApipData.length) { disablePlugin(); this.hide(); return; } getTTSComponent().setMediaContentData(ttsApipData); this.show(); if (!this.getState('sleep')) { this.setState('enabled', true); toggleTool(); } }); }, /** * Called during the runner's destroy phase */ destroy() { shortcut.remove(`.${this.getName()}`); }, /** * Enable the button */ enable() { this.button.enable(); }, /** * Disable the button */ disable() { this.button.disable(); }, /** * Show the button */ show() { this.button.show(); }, /** * Hide the button */ hide() { this.button.hide(); } }); return plugin; });