@pie-element/multiple-choice 9.13.0 → 9.13.1-next.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +19 -2
- package/lib/index.js.map +1 -1
- package/module/element.js +32 -1
- package/module/index.html +1 -1
- package/module/manifest.json +1 -1
- package/module/print.html +1 -1
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -277,7 +277,12 @@ var MultipleChoice = /*#__PURE__*/function (_HTMLElement) {
|
|
|
277
277
|
audio.removeEventListener('ended', handleEnded);
|
|
278
278
|
};
|
|
279
279
|
|
|
280
|
-
audio.addEventListener('ended', handleEnded);
|
|
280
|
+
audio.addEventListener('ended', handleEnded); // store references to remove later
|
|
281
|
+
|
|
282
|
+
_this2._audio = audio;
|
|
283
|
+
_this2._handlePlaying = handlePlaying;
|
|
284
|
+
_this2._handleEnded = handleEnded;
|
|
285
|
+
_this2._enableAudio = enableAudio;
|
|
281
286
|
observer.disconnect();
|
|
282
287
|
}
|
|
283
288
|
});
|
|
@@ -302,6 +307,16 @@ var MultipleChoice = /*#__PURE__*/function (_HTMLElement) {
|
|
|
302
307
|
window.removeEventListener('keydown', this._boundHandleKeyDown);
|
|
303
308
|
this._keyboardEventsEnabled = false;
|
|
304
309
|
}
|
|
310
|
+
|
|
311
|
+
document.removeEventListener('click', this._enableAudio);
|
|
312
|
+
|
|
313
|
+
if (this._audio) {
|
|
314
|
+
this._audio.removeEventListener('playing', this._handlePlaying);
|
|
315
|
+
|
|
316
|
+
this._audio.removeEventListener('ended', this._handleEnded);
|
|
317
|
+
|
|
318
|
+
this._audio = null;
|
|
319
|
+
}
|
|
305
320
|
}
|
|
306
321
|
/**
|
|
307
322
|
* Handles global keyboard events for selecting or toggling multiple-choice answers.
|
|
@@ -312,6 +327,8 @@ var MultipleChoice = /*#__PURE__*/function (_HTMLElement) {
|
|
|
312
327
|
}, {
|
|
313
328
|
key: "handleKeyDown",
|
|
314
329
|
value: function handleKeyDown(event) {
|
|
330
|
+
var _this$_model$choices;
|
|
331
|
+
|
|
315
332
|
if (!this._model || !this._session) {
|
|
316
333
|
return;
|
|
317
334
|
}
|
|
@@ -324,7 +341,7 @@ var MultipleChoice = /*#__PURE__*/function (_HTMLElement) {
|
|
|
324
341
|
|
|
325
342
|
var choiceIndex = keyToIndex(event.key);
|
|
326
343
|
|
|
327
|
-
if (choiceIndex === undefined || choiceIndex >= this._model.choices.length) {
|
|
344
|
+
if (choiceIndex === undefined || choiceIndex <= -1 || choiceIndex >= ((_this$_model$choices = this._model.choices) === null || _this$_model$choices === void 0 ? void 0 : _this$_model$choices.length)) {
|
|
328
345
|
return;
|
|
329
346
|
}
|
|
330
347
|
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":["log","isComplete","session","model","audioComplete","autoplayAudioEnabled","completeAudioEnabled","value","choiceMode","minSelections","maxSelections","selections","length","MultipleChoice","_model","_session","_boundHandleKeyDown","handleKeyDown","bind","_keyboardEventsEnabled","_rerender","element","React","createElement","Main","onChoiceChanged","_onChange","onShowCorrectToggle","setAttribute","setLangAttribute","ReactDOM","render","keyboardEventsEnabled","enableKeyboardEvents","leading","trailing","_dispatchResponseChanged","dispatchEvent","SessionChangedEvent","tagName","toLowerCase","_dispatchModelSet","ModelSetEvent","undefined","language","lang","slice","s","data","info","document","id","Object","assign","style","position","top","width","height","display","justifyContent","alignItems","background","zIndex","img","src","alt","appendChild","observer","MutationObserver","mutationsList","forEach","mutation","type","audio","querySelector","isInsidePrompt","closest","_createAudioInfoToast","container","enableAudio","play","removeChild","removeEventListener","setTimeout","paused","addEventListener","handlePlaying","audioStartTime","Date","getTime","handleEnded","audioEndTime","disconnect","observe","childList","subtree","window","event","keyToIndex","key","numOffset","letterOffset","test","charCodeAt","choiceIndex","choices","currentValue","choiceId","newValue","selected","includes","selector","HTMLElement"],"mappings":"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","sourcesContent":["import Main from './main';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport debounce from 'lodash/debounce';\nimport debug from 'debug';\nimport { ModelSetEvent, SessionChangedEvent } from '@pie-framework/pie-player-events';\nimport { renderMath } from '@pie-lib/pie-toolbox/math-rendering';\nimport { updateSessionValue, updateSessionMetadata } from './session-updater';\n\nconst log = debug('pie-ui:multiple-choice');\n\nexport const isComplete = (session, model, audioComplete) => {\n const { autoplayAudioEnabled, completeAudioEnabled } = model || {};\n\n if (autoplayAudioEnabled && completeAudioEnabled && !audioComplete) {\n return false;\n }\n\n if (!session || !session.value) {\n return false;\n }\n\n const { choiceMode, minSelections = 1, maxSelections } = model || {};\n const selections = session.value.length || 0;\n\n if (choiceMode === 'radio') {\n return !!selections;\n }\n\n if (selections < minSelections || selections > maxSelections) {\n return false;\n }\n\n return true;\n};\n\nexport default class MultipleChoice extends HTMLElement {\n constructor() {\n super();\n this._model = null;\n this._session = null;\n this.audioComplete = false;\n this._boundHandleKeyDown = this.handleKeyDown.bind(this);\n this._keyboardEventsEnabled = false;\n\n this._rerender = debounce(\n () => {\n if (this._model && this._session) {\n var element = React.createElement(Main, {\n model: this._model,\n session: this._session,\n onChoiceChanged: this._onChange.bind(this),\n onShowCorrectToggle: this.onShowCorrectToggle.bind(this),\n });\n\n //TODO: aria-label is set in the _rerender because we need to change it when the model.choiceMode is updated. Consider revisiting the placement of the aria-label setting in the _rerender\n this.setAttribute(\n 'aria-label',\n this._model.choiceMode === 'radio' ? 'Multiple Choice Question' : 'Multiple Correct Answer Question',\n );\n this.setAttribute('role', 'region');\n this.setLangAttribute();\n\n ReactDOM.render(element, this, () => {\n log('render complete - render math');\n renderMath(this);\n });\n\n if (this._model.keyboardEventsEnabled === true && !this._keyboardEventsEnabled) {\n this.enableKeyboardEvents();\n }\n } else {\n log('skip');\n }\n },\n 50,\n { leading: false, trailing: true },\n );\n\n this._dispatchResponseChanged = debounce(() => {\n this.dispatchEvent(\n new SessionChangedEvent(this.tagName.toLowerCase(), isComplete(this._session, this._model, this.audioComplete)),\n );\n });\n\n this._dispatchModelSet = debounce(\n () => {\n this.dispatchEvent(\n new ModelSetEvent(\n this.tagName.toLowerCase(),\n isComplete(this._session, this._model),\n this._model !== undefined,\n ),\n );\n },\n 50,\n { leading: false, trailing: true },\n );\n }\n\n onShowCorrectToggle() {\n renderMath(this);\n }\n\n setLangAttribute() {\n const language = this._model && typeof this._model.language ? this._model.language : '';\n const lang = language ? language.slice(0, 2) : 'en';\n this.setAttribute('lang', lang);\n }\n\n set model(s) {\n this._model = s;\n this._rerender();\n this._dispatchModelSet();\n }\n\n get session() {\n return this._session;\n }\n\n set session(s) {\n this._session = s;\n this._rerender();\n //TODO: remove this session-changed should only be emit on user change\n this._dispatchResponseChanged();\n }\n\n _onChange(data) {\n updateSessionValue(this._session, this._model.choiceMode, data);\n this._dispatchResponseChanged();\n this._rerender();\n }\n\n _createAudioInfoToast() {\n const info = document.createElement('div');\n info.id = 'play-audio-info';\n\n Object.assign(info.style, {\n position: 'absolute',\n top: 0,\n width:'100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background: 'white',\n zIndex: '1000'\n });\n\n const img = document.createElement('img');\n img.src = 'https://student.assessment.renaissance.com/ce/quizenginecap/assets/img/playAppsSel.gif';\n img.alt = 'Click anywhere to enable audio autoplay';\n img.width = 500;\n img.height = 300;\n\n info.appendChild(img);\n return info;\n }\n\n connectedCallback() {\n this._rerender();\n\n // Observation: audio in Chrome will have the autoplay attribute,\n // while other browsers will not have the autoplay attribute and will need a user interaction to play the audio\n // This workaround fixes the issue of audio being cached and played on any user interaction in Safari and Firefox\n const observer = new MutationObserver((mutationsList, observer) => {\n mutationsList.forEach((mutation) => {\n if (mutation.type === 'childList') {\n const audio = this.querySelector('audio');\n const isInsidePrompt = audio && audio.closest('#preview-prompt');\n\n if (!this._model) return;\n if (!this._model.autoplayAudioEnabled) return;\n if (audio && !isInsidePrompt) return;\n if (!audio) return;\n\n const info = this._createAudioInfoToast();\n const container = this.querySelector('#main-container');\n const enableAudio = () => {\n if (this.querySelector('#play-audio-info')) {\n audio.play();\n container.removeChild(info);\n }\n\n document.removeEventListener('click', enableAudio);\n };\n\n // if the audio is paused, it means the user has not interacted with the page yet and the audio will not play\n // FIX FOR SAFARI: play with a slight delay to check if autoplay was blocked\n setTimeout(() => {\n if (audio.paused && !this.querySelector('#play-audio-info')) {\n // add info message as a toast to enable audio playback\n container.appendChild(info);\n document.addEventListener('click', enableAudio);\n } else {\n document.removeEventListener('click', enableAudio);\n }\n }, 500);\n\n // we need to listen for the playing event to remove the toast in case the audio plays because of re-rendering\n const handlePlaying = () => {\n updateSessionMetadata(this._session, { audioStartTime: new Date().getTime() });\n \n const info = this.querySelector('#play-audio-info');\n if (info) {\n container.removeChild(info);\n }\n\n audio.removeEventListener('playing', handlePlaying);\n };\n\n audio.addEventListener('playing', handlePlaying);\n\n // we need to listen for the ended event to update the isComplete state\n const handleEnded = () => {\n updateSessionMetadata(this._session, { audioEndTime: new Date().getTime() });\n this.audioComplete = true;\n this._dispatchResponseChanged();\n audio.removeEventListener('ended', handleEnded);\n };\n\n audio.addEventListener('ended', handleEnded);\n\n observer.disconnect();\n }\n });\n });\n\n observer.observe(this, { childList: true, subtree: true });\n }\n\n enableKeyboardEvents() {\n if (!this._keyboardEventsEnabled) {\n window.addEventListener('keydown', this._boundHandleKeyDown);\n this._keyboardEventsEnabled = true;\n }\n }\n\n disconnectedCallback() {\n if (this._keyboardEventsEnabled) {\n window.removeEventListener('keydown', this._boundHandleKeyDown);\n this._keyboardEventsEnabled = false;\n }\n }\n\n /**\n * Handles global keyboard events for selecting or toggling multiple-choice answers.\n * Maps keys (1-9, 0, a-j, A-J) to choices and updates the session state accordingly.\n * Ensures valid key presses toggle or select the appropriate choice based on the model.\n */\n handleKeyDown(event) {\n if (!this._model || !this._session) {\n return;\n }\n\n const keyToIndex = (key) => {\n const numOffset = key >= '1' && key <= '9' ? key - '1' : key === '0' ? 9 : -1;\n const letterOffset = /^[a-jA-J]$/.test(key) ? key.toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0) : -1;\n return numOffset >= 0 ? numOffset : letterOffset;\n };\n\n const choiceIndex = keyToIndex(event.key);\n\n if (choiceIndex === undefined || choiceIndex >= this._model.choices.length) {\n return;\n }\n\n const currentValue = this._session.value || [];\n const choiceId = this._model.choices[choiceIndex].value;\n\n const newValue = {\n value: choiceId,\n selected: !currentValue.includes(choiceId),\n selector: 'Keyboard',\n };\n\n this._onChange(newValue);\n }\n}\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"names":["log","isComplete","session","model","audioComplete","autoplayAudioEnabled","completeAudioEnabled","value","choiceMode","minSelections","maxSelections","selections","length","MultipleChoice","_model","_session","_boundHandleKeyDown","handleKeyDown","bind","_keyboardEventsEnabled","_rerender","element","React","createElement","Main","onChoiceChanged","_onChange","onShowCorrectToggle","setAttribute","setLangAttribute","ReactDOM","render","keyboardEventsEnabled","enableKeyboardEvents","leading","trailing","_dispatchResponseChanged","dispatchEvent","SessionChangedEvent","tagName","toLowerCase","_dispatchModelSet","ModelSetEvent","undefined","language","lang","slice","s","data","info","document","id","Object","assign","style","position","top","width","height","display","justifyContent","alignItems","background","zIndex","img","src","alt","appendChild","observer","MutationObserver","mutationsList","forEach","mutation","type","audio","querySelector","isInsidePrompt","closest","_createAudioInfoToast","container","enableAudio","play","removeChild","removeEventListener","setTimeout","paused","addEventListener","handlePlaying","audioStartTime","Date","getTime","handleEnded","audioEndTime","_audio","_handlePlaying","_handleEnded","_enableAudio","disconnect","observe","childList","subtree","window","event","keyToIndex","key","numOffset","letterOffset","test","charCodeAt","choiceIndex","choices","currentValue","choiceId","newValue","selected","includes","selector","HTMLElement"],"mappings":"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","sourcesContent":["import Main from './main';\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport debounce from 'lodash/debounce';\nimport debug from 'debug';\nimport { ModelSetEvent, SessionChangedEvent } from '@pie-framework/pie-player-events';\nimport { renderMath } from '@pie-lib/pie-toolbox/math-rendering';\nimport { updateSessionValue, updateSessionMetadata } from './session-updater';\n\nconst log = debug('pie-ui:multiple-choice');\n\nexport const isComplete = (session, model, audioComplete) => {\n const { autoplayAudioEnabled, completeAudioEnabled } = model || {};\n\n if (autoplayAudioEnabled && completeAudioEnabled && !audioComplete) {\n return false;\n }\n\n if (!session || !session.value) {\n return false;\n }\n\n const { choiceMode, minSelections = 1, maxSelections } = model || {};\n const selections = session.value.length || 0;\n\n if (choiceMode === 'radio') {\n return !!selections;\n }\n\n if (selections < minSelections || selections > maxSelections) {\n return false;\n }\n\n return true;\n};\n\nexport default class MultipleChoice extends HTMLElement {\n constructor() {\n super();\n this._model = null;\n this._session = null;\n this.audioComplete = false;\n this._boundHandleKeyDown = this.handleKeyDown.bind(this);\n this._keyboardEventsEnabled = false;\n\n this._rerender = debounce(\n () => {\n if (this._model && this._session) {\n var element = React.createElement(Main, {\n model: this._model,\n session: this._session,\n onChoiceChanged: this._onChange.bind(this),\n onShowCorrectToggle: this.onShowCorrectToggle.bind(this),\n });\n\n //TODO: aria-label is set in the _rerender because we need to change it when the model.choiceMode is updated. Consider revisiting the placement of the aria-label setting in the _rerender\n this.setAttribute(\n 'aria-label',\n this._model.choiceMode === 'radio' ? 'Multiple Choice Question' : 'Multiple Correct Answer Question',\n );\n this.setAttribute('role', 'region');\n this.setLangAttribute();\n\n ReactDOM.render(element, this, () => {\n log('render complete - render math');\n renderMath(this);\n });\n\n if (this._model.keyboardEventsEnabled === true && !this._keyboardEventsEnabled) {\n this.enableKeyboardEvents();\n }\n } else {\n log('skip');\n }\n },\n 50,\n { leading: false, trailing: true },\n );\n\n this._dispatchResponseChanged = debounce(() => {\n this.dispatchEvent(\n new SessionChangedEvent(this.tagName.toLowerCase(), isComplete(this._session, this._model, this.audioComplete)),\n );\n });\n\n this._dispatchModelSet = debounce(\n () => {\n this.dispatchEvent(\n new ModelSetEvent(\n this.tagName.toLowerCase(),\n isComplete(this._session, this._model),\n this._model !== undefined,\n ),\n );\n },\n 50,\n { leading: false, trailing: true },\n );\n }\n\n onShowCorrectToggle() {\n renderMath(this);\n }\n\n setLangAttribute() {\n const language = this._model && typeof this._model.language ? this._model.language : '';\n const lang = language ? language.slice(0, 2) : 'en';\n this.setAttribute('lang', lang);\n }\n\n set model(s) {\n this._model = s;\n this._rerender();\n this._dispatchModelSet();\n }\n\n get session() {\n return this._session;\n }\n\n set session(s) {\n this._session = s;\n this._rerender();\n //TODO: remove this session-changed should only be emit on user change\n this._dispatchResponseChanged();\n }\n\n _onChange(data) {\n updateSessionValue(this._session, this._model.choiceMode, data);\n this._dispatchResponseChanged();\n this._rerender();\n }\n\n _createAudioInfoToast() {\n const info = document.createElement('div');\n info.id = 'play-audio-info';\n\n Object.assign(info.style, {\n position: 'absolute',\n top: 0,\n width:'100%',\n height: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background: 'white',\n zIndex: '1000'\n });\n\n const img = document.createElement('img');\n img.src = 'https://student.assessment.renaissance.com/ce/quizenginecap/assets/img/playAppsSel.gif';\n img.alt = 'Click anywhere to enable audio autoplay';\n img.width = 500;\n img.height = 300;\n\n info.appendChild(img);\n return info;\n }\n\n connectedCallback() {\n this._rerender();\n\n // Observation: audio in Chrome will have the autoplay attribute,\n // while other browsers will not have the autoplay attribute and will need a user interaction to play the audio\n // This workaround fixes the issue of audio being cached and played on any user interaction in Safari and Firefox\n const observer = new MutationObserver((mutationsList, observer) => {\n mutationsList.forEach((mutation) => {\n if (mutation.type === 'childList') {\n const audio = this.querySelector('audio');\n const isInsidePrompt = audio && audio.closest('#preview-prompt');\n\n if (!this._model) return;\n if (!this._model.autoplayAudioEnabled) return;\n if (audio && !isInsidePrompt) return;\n if (!audio) return;\n\n const info = this._createAudioInfoToast();\n const container = this.querySelector('#main-container');\n const enableAudio = () => {\n if (this.querySelector('#play-audio-info')) {\n audio.play();\n container.removeChild(info);\n }\n\n document.removeEventListener('click', enableAudio);\n };\n\n // if the audio is paused, it means the user has not interacted with the page yet and the audio will not play\n // FIX FOR SAFARI: play with a slight delay to check if autoplay was blocked\n setTimeout(() => {\n if (audio.paused && !this.querySelector('#play-audio-info')) {\n // add info message as a toast to enable audio playback\n container.appendChild(info);\n document.addEventListener('click', enableAudio);\n } else {\n document.removeEventListener('click', enableAudio);\n }\n }, 500);\n\n // we need to listen for the playing event to remove the toast in case the audio plays because of re-rendering\n const handlePlaying = () => {\n updateSessionMetadata(this._session, { audioStartTime: new Date().getTime() });\n\n const info = this.querySelector('#play-audio-info');\n if (info) {\n container.removeChild(info);\n }\n\n audio.removeEventListener('playing', handlePlaying);\n };\n\n audio.addEventListener('playing', handlePlaying);\n\n // we need to listen for the ended event to update the isComplete state\n const handleEnded = () => {\n updateSessionMetadata(this._session, { audioEndTime: new Date().getTime() });\n this.audioComplete = true;\n this._dispatchResponseChanged();\n audio.removeEventListener('ended', handleEnded);\n };\n\n audio.addEventListener('ended', handleEnded);\n\n // store references to remove later\n this._audio = audio;\n this._handlePlaying = handlePlaying;\n this._handleEnded = handleEnded;\n this._enableAudio = enableAudio;\n\n observer.disconnect();\n }\n });\n });\n\n observer.observe(this, { childList: true, subtree: true });\n }\n\n enableKeyboardEvents() {\n if (!this._keyboardEventsEnabled) {\n window.addEventListener('keydown', this._boundHandleKeyDown);\n this._keyboardEventsEnabled = true;\n }\n }\n\n disconnectedCallback() {\n if (this._keyboardEventsEnabled) {\n window.removeEventListener('keydown', this._boundHandleKeyDown);\n this._keyboardEventsEnabled = false;\n }\n\n document.removeEventListener('click', this._enableAudio);\n\n if (this._audio) {\n this._audio.removeEventListener('playing', this._handlePlaying);\n this._audio.removeEventListener('ended', this._handleEnded);\n this._audio = null;\n }\n }\n\n /**\n * Handles global keyboard events for selecting or toggling multiple-choice answers.\n * Maps keys (1-9, 0, a-j, A-J) to choices and updates the session state accordingly.\n * Ensures valid key presses toggle or select the appropriate choice based on the model.\n */\n handleKeyDown(event) {\n if (!this._model || !this._session) {\n return;\n }\n\n const keyToIndex = (key) => {\n const numOffset = key >= '1' && key <= '9' ? key - '1' : key === '0' ? 9 : -1;\n const letterOffset = /^[a-jA-J]$/.test(key) ? key.toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0) : -1;\n return numOffset >= 0 ? numOffset : letterOffset;\n };\n\n const choiceIndex = keyToIndex(event.key);\n\n if (choiceIndex === undefined || choiceIndex <= -1 || choiceIndex >= this._model.choices?.length) {\n return;\n }\n\n const currentValue = this._session.value || [];\n const choiceId = this._model.choices[choiceIndex].value;\n\n const newValue = {\n value: choiceId,\n selected: !currentValue.includes(choiceId),\n selector: 'Keyboard',\n };\n\n this._onChange(newValue);\n }\n}\n"],"file":"index.js"}
|
package/module/element.js
CHANGED
|
@@ -13101,6 +13101,27 @@ const ReactDOM = _dll_react_dom;
|
|
|
13101
13101
|
const {debounce: debounce} = _dll_lodash;
|
|
13102
13102
|
const debug = _dll_debug;
|
|
13103
13103
|
const {renderMath: renderMath} = _dll_pie_lib__pie_toolbox_math_rendering;
|
|
13104
|
+
function _optionalChain(ops) {
|
|
13105
|
+
let lastAccessLHS = undefined;
|
|
13106
|
+
let value = ops[0];
|
|
13107
|
+
let i = 1;
|
|
13108
|
+
while (i < ops.length) {
|
|
13109
|
+
const op = ops[i];
|
|
13110
|
+
const fn = ops[i + 1];
|
|
13111
|
+
i += 2;
|
|
13112
|
+
if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
|
|
13113
|
+
return undefined;
|
|
13114
|
+
}
|
|
13115
|
+
if (op === 'access' || op === 'optionalAccess') {
|
|
13116
|
+
lastAccessLHS = value;
|
|
13117
|
+
value = fn(value);
|
|
13118
|
+
} else if (op === 'call' || op === 'optionalCall') {
|
|
13119
|
+
value = fn((...args) => value.call(lastAccessLHS, ...args));
|
|
13120
|
+
lastAccessLHS = undefined;
|
|
13121
|
+
}
|
|
13122
|
+
}
|
|
13123
|
+
return value;
|
|
13124
|
+
}
|
|
13104
13125
|
const log = debug('pie-ui:multiple-choice');
|
|
13105
13126
|
const isComplete = (session, model, audioComplete) => {
|
|
13106
13127
|
const {autoplayAudioEnabled, completeAudioEnabled} = model || ({});
|
|
@@ -13259,6 +13280,10 @@ class MultipleChoice extends HTMLElement {
|
|
|
13259
13280
|
audio.removeEventListener('ended', handleEnded);
|
|
13260
13281
|
};
|
|
13261
13282
|
audio.addEventListener('ended', handleEnded);
|
|
13283
|
+
this._audio = audio;
|
|
13284
|
+
this._handlePlaying = handlePlaying;
|
|
13285
|
+
this._handleEnded = handleEnded;
|
|
13286
|
+
this._enableAudio = enableAudio;
|
|
13262
13287
|
observer.disconnect();
|
|
13263
13288
|
}
|
|
13264
13289
|
});
|
|
@@ -13279,6 +13304,12 @@ class MultipleChoice extends HTMLElement {
|
|
|
13279
13304
|
window.removeEventListener('keydown', this._boundHandleKeyDown);
|
|
13280
13305
|
this._keyboardEventsEnabled = false;
|
|
13281
13306
|
}
|
|
13307
|
+
document.removeEventListener('click', this._enableAudio);
|
|
13308
|
+
if (this._audio) {
|
|
13309
|
+
this._audio.removeEventListener('playing', this._handlePlaying);
|
|
13310
|
+
this._audio.removeEventListener('ended', this._handleEnded);
|
|
13311
|
+
this._audio = null;
|
|
13312
|
+
}
|
|
13282
13313
|
}
|
|
13283
13314
|
handleKeyDown(event) {
|
|
13284
13315
|
if (!this._model || !this._session) {
|
|
@@ -13290,7 +13321,7 @@ class MultipleChoice extends HTMLElement {
|
|
|
13290
13321
|
return numOffset >= 0 ? numOffset : letterOffset;
|
|
13291
13322
|
};
|
|
13292
13323
|
const choiceIndex = keyToIndex(event.key);
|
|
13293
|
-
if (choiceIndex === undefined || choiceIndex >= this._model.choices.length) {
|
|
13324
|
+
if (choiceIndex === undefined || choiceIndex <= -1 || choiceIndex >= _optionalChain([this, 'access', _ => _._model, 'access', _2 => _2.choices, 'optionalAccess', _3 => _3.length])) {
|
|
13294
13325
|
return;
|
|
13295
13326
|
}
|
|
13296
13327
|
const currentValue = this._session.value || [];
|
package/module/index.html
CHANGED
package/module/manifest.json
CHANGED
package/module/print.html
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-element/multiple-choice",
|
|
3
3
|
"repository": "pie-framework/pie-elements",
|
|
4
|
-
"version": "9.13.
|
|
4
|
+
"version": "9.13.1-next.11+d030a51b5",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"react-test-renderer": "^16.3.2",
|
|
20
20
|
"react-transition-group": "^2.3.1"
|
|
21
21
|
},
|
|
22
|
-
"gitHead": "
|
|
22
|
+
"gitHead": "d030a51b53d7c9188f667389ee6dbac0950ede47",
|
|
23
23
|
"scripts": {
|
|
24
24
|
"postpublish": "../../scripts/postpublish"
|
|
25
25
|
},
|