@oat-sa/tao-test-runner-qti
Version:
TAO Test Runner QTI implementation
212 lines (198 loc) • 7.27 kB
JavaScript
define(['lodash', 'jquery', 'core/eventifier', 'ui/highlighter'], function (_, $, eventifier, highlighterFactory) { 'use strict';
_ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
$ = $ && Object.prototype.hasOwnProperty.call($, 'default') ? $['default'] : $;
eventifier = eventifier && Object.prototype.hasOwnProperty.call(eventifier, 'default') ? eventifier['default'] : eventifier;
highlighterFactory = highlighterFactory && Object.prototype.hasOwnProperty.call(highlighterFactory, 'default') ? highlighterFactory['default'] : highlighterFactory;
/**
* 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;
*/
var prevSelection = [];
var selection;
if (!window.getSelection) throw new Error('Browser does not support getSelection()');
selection = window.getSelection();
/**
* Returns an array of active ranges.
* If browser doesn't support multiple Ranges, returns only the first range
* see note on https://w3c.github.io/selection-api/#methods
*
* @returns {Range[]}
*/
function getAllRanges() {
var i,
allRanges = [];
for (i = 0; i < selection.rangeCount; i++) {
allRanges.push(selection.getRangeAt(i));
}
return allRanges;
}
/**
* Discards the global text selection from the browser (window.selection)
*/
function discardSelection() {
// delay discarding, to allow time for multiple highlighters logic
setTimeout(function () {
selection.removeAllRanges();
}, 250);
}
/**
* The highlighter Factory
* @param {Object} options
* @param {String} [options.className]
* @param {String} [options.containerSelector]
* @param {Array} [options.containersBlackList]
* @param {String} [options.id]
* @returns {Object} the highlighter instance
*/
function testHighlighterFactory(options) {
/**
* Is this highlighter enabled or disabled?
* @type {boolean}
*/
var enabled = true;
/**
* Are we in highlight mode, meaning that each new selection is automatically highlighted
* without having to press any button
* @type {boolean}
*/
var isHighlighting = false;
/**
* The helper that does the highlight magic
*/
var highlightHelper = highlighterFactory({
className: options.className || 'txt-user-highlight',
containerSelector: options.containerSelector || '.qti-itemBody',
containersBlackList: options.containersBlackList || [],
clearOnClick: true
});
//add event to automatically highlight the recently made selection if needed
$(document).on('mouseup.highlighter', function () {
if (isHighlighting && !selection.isCollapsed) {
highlightHelper.highlightRanges(getAllRanges());
discardSelection();
}
});
//add event to automatically highlight the recently made selection if needed
//added touch event (as from TAO-6578)
$(document).on('touchend.highlighter', function () {
if (isHighlighting && !selection.isCollapsed) {
highlightHelper.highlightRanges(getAllRanges());
}
});
// iOS devices clears selection after click on button,
// so we store prev selection for this devices to be able
// to use it after click on highlight button
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
$(document).on('selectionchange', function () {
if (!isHighlighting) {
prevSelection = _.clone(getAllRanges(), true);
}
});
}
/**
* The highlighter instance
*/
return eventifier({
/**
* Enable this instance
*/
enable: function enable() {
enabled = true;
},
/**
* Disable this instance
*/
disable: function disable() {
enabled = false;
},
/**
* Is this instance currently enabled?
* @returns {Boolean}
*/
isEnabled: function isEnabled() {
return enabled;
},
/**
* toggle highlighting mode on and off
* @param {Boolean} bool - wanted state
*/
toggleHighlighting: function toggleHighlighting(bool) {
isHighlighting = bool;
if (isHighlighting) {
this.trigger('start');
$('.qti-itemBody').toggleClass('highlighter-cursor', true);
} else {
this.trigger('end');
$('.qti-itemBody').toggleClass('highlighter-cursor', false);
}
return this;
},
/**
* Either highlight the current or selection, or toggle highlighting mode
*/
highlight: function highlight() {
if (!isHighlighting) {
if (!selection.isCollapsed) {
this.toggleHighlighting(true);
highlightHelper.highlightRanges(getAllRanges());
this.toggleHighlighting(false);
discardSelection();
} else if (prevSelection[0] && !prevSelection[0].collapsed) {
this.toggleHighlighting(true);
highlightHelper.highlightRanges(prevSelection);
this.toggleHighlighting(false);
discardSelection();
} else {
this.toggleHighlighting(true);
}
} else {
this.toggleHighlighting(false);
}
},
/**
* restore the highlight from a given index
* @param {Array} index
*/
restoreIndex: function restoreIndex(index) {
if (index && index.length > 0) {
highlightHelper.highlightFromIndex(index);
}
},
/**
* Get the current index
* @returns {Array} index
*/
getIndex: function getIndex() {
return highlightHelper.getHighlightIndex();
},
/**
* remove all highlights
*/
clearHighlights: function clearHighlights() {
highlightHelper.clearHighlights();
selection.removeAllRanges();
},
/**
* Getter for the instance's id
* @returns {String}
*/
getId: function getId() {
return options.id;
}
});
}
return testHighlighterFactory;
});