var H5P = H5P || {}; /** * Transition contains helper function relevant for transitioning */ H5P.Transition = (function ($) { /** * @class * @namespace H5P */ Transition = {}; /** * @private */ Transition.transitionEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'transition': 'transitionend', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd' }; /** * @private */ Transition.cache = []; /** * Get the vendor property name for an event * * @function H5P.Transition.getVendorPropertyName * @static * @private * @param {string} prop Generic property name * @return {string} Vendor specific property name */ Transition.getVendorPropertyName = function (prop) { if (Transition.cache[prop] !== undefined) { return Transition.cache[prop]; } var div = document.createElement('div'); // Handle unprefixed versions (FF16+, for example) if (prop in div.style) { Transition.cache[prop] = prop; } else { var prefixes = ['Moz', 'Webkit', 'O', 'ms']; var prop_ = prop.charAt(0).toUpperCase() + prop.substr(1); if (prop in div.style) { Transition.cache[prop] = prop; } else { for (var i = 0; i < prefixes.length; ++i) { var vendorProp = prefixes[i] + prop_; if (vendorProp in div.style) { Transition.cache[prop] = vendorProp; break; } } } } return Transition.cache[prop]; }; /** * Get the name of the transition end event * * @static * @private * @return {string} description */ Transition.getTransitionEndEventName = function () { return Transition.transitionEndEventNames[Transition.getVendorPropertyName('transition')] || undefined; }; /** * Helper function for listening on transition end events * * @function H5P.Transition.onTransitionEnd * @static * @param {domElement} $element The element which is transitioned * @param {function} callback The callback to be invoked when transition is finished * @param {number} timeout Timeout in milliseconds. Fallback if transition event is never fired */ Transition.onTransitionEnd = function ($element, callback, timeout) { // Fallback on 1 second if transition event is not supported/triggered timeout = timeout || 1000; Transition.transitionEndEventName = Transition.transitionEndEventName || Transition.getTransitionEndEventName(); var callbackCalled = false; var doCallback = function () { if (callbackCalled) { return; } $element.off(Transition.transitionEndEventName, callback); callbackCalled = true; clearTimeout(timer); callback(); }; var timer = setTimeout(function () { doCallback(); }, timeout); $element.on(Transition.transitionEndEventName, function () { doCallback(); }); }; /** * Wait for a transition - when finished, invokes next in line * * @private * * @param {Object[]} transitions Array of transitions * @param {H5P.jQuery} transitions[].$element Dom element transition is performed on * @param {number=} transitions[].timeout Timeout fallback if transition end never is triggered * @param {bool=} transitions[].break If true, sequence breaks after this transition * @param {number} index The index for current transition */ var runSequence = function (transitions, index) { if (index >= transitions.length) { return; } var transition = transitions[index]; H5P.Transition.onTransitionEnd(transition.$element, function () { if (transition.end) { transition.end(); } if (transition.break !== true) { runSequence(transitions, index+1); } }, transition.timeout || undefined); }; /** * Run a sequence of transitions * * @function H5P.Transition.sequence * @static * @param {Object[]} transitions Array of transitions * @param {H5P.jQuery} transitions[].$element Dom element transition is performed on * @param {number=} transitions[].timeout Timeout fallback if transition end never is triggered * @param {bool=} transitions[].break If true, sequence breaks after this transition */ Transition.sequence = function (transitions) { runSequence(transitions, 0); }; return Transition; })(H5P.jQuery); ; var H5P = H5P || {}; /** * Class responsible for creating a help text dialog */ H5P.JoubelHelpTextDialog = (function ($) { var numInstances = 0; /** * Display a pop-up containing a message. * * @param {H5P.jQuery} $container The container which message dialog will be appended to * @param {string} message The message * @param {string} closeButtonTitle The title for the close button * @return {H5P.jQuery} */ function JoubelHelpTextDialog(header, message, closeButtonTitle) { H5P.EventDispatcher.call(this); var self = this; numInstances++; var headerId = 'joubel-help-text-header-' + numInstances; var helpTextId = 'joubel-help-text-body-' + numInstances; var $helpTextDialogBox = $('
' + instance.options.description + '
' }; definition.type = 'http://adlnet.gov/expapi/activities/cmi.interaction'; definition.interactionType = 'fill-in'; const solutionsAll = instance.options.cards.map(function (card) { return H5P.Flashcards.splitAlternatives(card.answer); }); // Fallback CRP, could cause computational hazard if computed fully const crpAnswers = solutionsAll.map(function (solutions) { return solutions[0]; }).join('[,]'); definition.correctResponsesPattern = [ '{case_matters=' + instance.options.caseSensitive + '}' + crpAnswers ]; const cardDescriptions = instance.options.cards.map(function (card) { return '' + card.text + ' ' + placeHolder + '
'; }).join(''); definition.description['en-US'] += cardDescriptions; /* * Add H5P Alternative extension which provides all combinations of * different answers. Reporting software will need to support this extension * for alternatives to work. */ definition.extensions = definition.extensions || {}; definition.extensions[XAPI_CASE_SENSITIVITY] = instance.options.caseSensitive; definition.extensions[XAPI_ALTERNATIVE_EXTENSION] = solutionsAll; return definition; }; return { getXapiEvent: getXapiEvent, }; })(H5P.jQuery); ; /** * Flashcards module. * * @param {H5P.jQuery} $ */ H5P.Flashcards = (function ($, XapiGenerator) { C.counter = 0; /** * Initialize module. * * @param {Object} options Run parameters * @param {Number} id Content identification */ function C(options, id) { H5P.EventDispatcher.call(this); this.answers = []; this.numAnswered = 0; this.contentId = this.id = id; this.options = $.extend({}, { description: "What does the card mean?", progressText: "Card @card of @total", next: "Next", previous: "Previous", checkAnswerText: "Check answer", showSolutionsRequiresInput: true, defaultAnswerText: "Your answer", correctAnswerText: "Correct", incorrectAnswerText: "Incorrect", showSolutionText: "Correct answer(s)", answerShortText: "A:", informationText: "Information", caseSensitive: false, randomCards: false, results: "Results", ofCorrect: "@score of @total correct", showResults: "Show results", retry : "Retry", cardAnnouncement: 'Incorrect answer. Correct answer was @answer', pageAnnouncement: 'Page @current of @total', correctAnswerAnnouncement: '@answer is correct!' }, options); this.$images = []; this.hasBeenReset = false; this.on('resize', this.resize, this); if (this.options.randomCards === true) { this.options.cards = this.shuffle(this.options.cards); } } C.prototype = Object.create(H5P.EventDispatcher.prototype); C.prototype.constructor = C; /** * Process HTML escaped string for use as attribute value, * e.g. for alt text or title attributes. * * @param {string} value * @return {string} WARNING! Do NOT use for innerHTML. */ const massageAttributeOutput = value => { const dparser = new DOMParser().parseFromString(value, 'text/html'); const div = document.createElement('div'); div.innerHTML = dparser.documentElement.textContent;; return div.textContent || div.innerText || ''; }; /** * Append field to wrapper. * * @param {H5P.jQuery} $container */ C.prototype.attach = function ($container) { var that = this; if (this.isRoot()) { this.setActivityStarted(); } this.$container = $container .addClass('h5p-flashcards') .html('