@pie-element/hotspot 7.5.3-next.21 → 7.5.3-next.25
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/controller/lib/index.js +5 -1
- package/controller/lib/index.js.map +1 -1
- package/controller/src/index.js +4 -0
- package/docs/pie-schema.json +10 -0
- package/docs/pie-schema.json.md +8 -0
- package/lib/hotspot/index.js +8 -3
- package/lib/hotspot/index.js.map +1 -1
- package/lib/index.js +114 -3
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/hotspot/index.jsx +5 -1
- package/src/index.js +108 -1
package/controller/lib/index.js
CHANGED
|
@@ -56,7 +56,9 @@ function model(question, session, env) {
|
|
|
56
56
|
prompt = normalizedQuestion.prompt,
|
|
57
57
|
shapes = normalizedQuestion.shapes,
|
|
58
58
|
language = normalizedQuestion.language,
|
|
59
|
-
fontSizeFactor = normalizedQuestion.fontSizeFactor
|
|
59
|
+
fontSizeFactor = normalizedQuestion.fontSizeFactor,
|
|
60
|
+
autoplayAudioEnabled = normalizedQuestion.autoplayAudioEnabled,
|
|
61
|
+
completeAudioEnabled = normalizedQuestion.completeAudioEnabled;
|
|
60
62
|
|
|
61
63
|
var _ref = shapes || {},
|
|
62
64
|
rectangles = _ref.rectangles,
|
|
@@ -77,6 +79,8 @@ function model(question, session, env) {
|
|
|
77
79
|
partialScoring: partialScoring,
|
|
78
80
|
language: language,
|
|
79
81
|
fontSizeFactor: fontSizeFactor,
|
|
82
|
+
autoplayAudioEnabled: autoplayAudioEnabled,
|
|
83
|
+
completeAudioEnabled: completeAudioEnabled,
|
|
80
84
|
shapes: _objectSpread(_objectSpread({}, shapes), {}, {
|
|
81
85
|
// eslint-disable-next-line no-unused-vars
|
|
82
86
|
rectangles: (rectangles || []).map(function (_ref2) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":["log","normalize","question","defaults","model","session","env","normalizedQuestion","imageUrl","dimensions","hotspotColor","hoverOutlineColor","selectedHotspotColor","multipleCorrect","outlineColor","partialScoring","prompt","shapes","language","fontSizeFactor","rectangles","polygons","circles","Promise","resolve","out","disabled","mode","map","index","rectProps","polyProps","circleProps","responseCorrect","undefined","extraCSSRules","role","rationale","rationaleEnabled","teacherInstructions","teacherInstructionsEnabled","promptEnabled","strokeWidth","createDefaultModel","getScore","config","answers","partialScoringEnabled","enabled","correctAnswers","selectedChoices","choices","correctChoices","filter","choice","correct","forEach","shape","selected","answer","id","correctlySelected","extraAnswers","length","total","str","toFixed","parseFloat","outcome","score","empty","returnShapesCorrect","i","push","createCorrectResponseSession","rectangleCorrect","polygonsCorrect","circlesCorrect","getInnerText","html","replaceAll","getContent","replace","validate","minShapes","maxShapes","maxSelections","errors","field","required","allShapes","Object","values","reduce","acc","nbOfSelections","nbOfShapes","selections"],"mappings":"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","sourcesContent":["import debug from 'debug';\nimport isEmpty from 'lodash/isEmpty';\nimport { partialScoring } from '@pie-lib/pie-toolbox/controller-utils';\n\nimport { isResponseCorrect } from './utils';\n\nimport defaults from './defaults';\n\nconst log = debug('pie-elements:hotspot:controller');\n\nexport const normalize = (question) => ({\n ...defaults,\n ...question,\n});\n\nexport function model(question, session, env) {\n const normalizedQuestion = normalize(question);\n const {\n imageUrl,\n dimensions,\n hotspotColor,\n hoverOutlineColor,\n selectedHotspotColor,\n multipleCorrect,\n outlineColor,\n partialScoring,\n prompt,\n shapes,\n language,\n fontSizeFactor,\n } = normalizedQuestion;\n const { rectangles, polygons, circles } = shapes || {};\n\n return new Promise((resolve) => {\n const out = {\n disabled: env.mode !== 'gather',\n mode: env.mode,\n dimensions,\n imageUrl,\n outlineColor,\n hotspotColor,\n hoverOutlineColor,\n selectedHotspotColor,\n multipleCorrect,\n partialScoring,\n language,\n fontSizeFactor,\n shapes: {\n ...shapes,\n // eslint-disable-next-line no-unused-vars\n rectangles: (rectangles || []).map(({ index, ...rectProps }) => ({ ...rectProps })),\n // eslint-disable-next-line no-unused-vars\n polygons: (polygons || []).map(({ index, ...polyProps }) => ({ ...polyProps })),\n // eslint-disable-next-line no-unused-vars\n circles: (circles || []).map(({ index, ...circleProps }) => ({ ...circleProps })),\n },\n responseCorrect: env.mode === 'evaluate' ? isResponseCorrect(normalizedQuestion, session) : undefined,\n extraCSSRules: normalizedQuestion.extraCSSRules,\n };\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n out.rationale = normalizedQuestion.rationaleEnabled ? normalizedQuestion.rationale : null;\n out.teacherInstructions = normalizedQuestion.teacherInstructionsEnabled\n ? normalizedQuestion.teacherInstructions\n : null;\n } else {\n out.rationale = null;\n out.teacherInstructions = null;\n }\n\n out.prompt = normalizedQuestion.promptEnabled ? prompt : null;\n out.strokeWidth = normalizedQuestion.strokeWidth;\n\n // console.log(out);\n resolve(out);\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise((resolve) => {\n resolve({\n ...defaults,\n ...model,\n });\n });\n\nconst getScore = (config, session, env = {}) => {\n const { answers } = session || {};\n\n if (!config.shapes || (!config.shapes.rectangles && !config.shapes.polygons && !config.shapes.circles)) {\n return 0;\n }\n\n const { shapes: { rectangles = [], polygons = [], circles = [] } = {} } = config;\n const partialScoringEnabled = partialScoring.enabled(config, env);\n\n if (!partialScoringEnabled) {\n return isResponseCorrect(config, session) ? 1 : 0;\n }\n\n let correctAnswers = 0;\n let selectedChoices = 0;\n\n const choices = [...rectangles, ...polygons, ...circles];\n\n const correctChoices = choices.filter((choice) => choice.correct);\n\n choices.forEach((shape) => {\n const selected = answers && answers.filter((answer) => answer.id === shape.id)[0];\n const correctlySelected = shape.correct && selected;\n\n if (selected) {\n selectedChoices += 1;\n }\n\n if (correctlySelected) {\n correctAnswers += 1;\n }\n });\n\n const extraAnswers = selectedChoices > correctChoices.length ? selectedChoices - correctChoices.length : 0;\n\n const total = correctChoices.length === 0 ? 1 : correctChoices.length;\n const str = ((correctAnswers - extraAnswers) / total).toFixed(2);\n\n return str < 0 ? 0 : parseFloat(str);\n};\n\nexport function outcome(config, session, env = {}) {\n return new Promise((resolve) => {\n log('outcome...');\n\n if (!session || isEmpty(session)) {\n resolve({ score: 0, empty: true });\n }\n\n if (session.answers) {\n const score = getScore(config, session, env);\n resolve({ score });\n } else {\n resolve({ score: 0, empty: true });\n }\n });\n}\n\nconst returnShapesCorrect = (shapes) => {\n let answers = [];\n\n shapes.forEach((i) => {\n const { correct, id } = i;\n if (correct) {\n answers.push({ id });\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { shapes: { rectangles = [], circles = [], polygons = {} } = {} } = question;\n\n const rectangleCorrect = returnShapesCorrect(rectangles);\n const polygonsCorrect = returnShapesCorrect(polygons);\n const circlesCorrect = returnShapesCorrect(circles);\n\n resolve({\n answers: [...rectangleCorrect, ...polygonsCorrect, ...circlesCorrect],\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img and iframe\nconst getContent = (html) => (html || '').replace(/(<(?!img|iframe)([^>]+)>)/gi, '');\n\nexport const validate = (model = {}, config = {}) => {\n const { shapes } = model;\n const { minShapes = 2, maxShapes, maxSelections } = config;\n const errors = {};\n\n ['teacherInstructions', 'prompt', 'rationale'].forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n const allShapes = Object.values(shapes || {}).reduce((acc, shape) => [...acc, ...shape], []);\n\n const nbOfSelections = (allShapes || []).reduce((acc, shape) => (shape.correct ? acc + 1 : acc), 0);\n\n const nbOfShapes = (allShapes || []).length;\n\n if (nbOfShapes < minShapes) {\n errors.shapes = `There should be at least ${minShapes} shapes defined.`;\n } else if (nbOfShapes > maxShapes) {\n errors.shapes = `No more than ${maxShapes} shapes should be defined.`;\n }\n\n if (nbOfSelections < 1) {\n errors.selections = 'There should be at least 1 shape selected.';\n } else if (nbOfSelections > maxSelections) {\n errors.selections = `No more than ${maxSelections} shapes should be selected.`;\n }\n\n return errors;\n};\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"names":["log","normalize","question","defaults","model","session","env","normalizedQuestion","imageUrl","dimensions","hotspotColor","hoverOutlineColor","selectedHotspotColor","multipleCorrect","outlineColor","partialScoring","prompt","shapes","language","fontSizeFactor","autoplayAudioEnabled","completeAudioEnabled","rectangles","polygons","circles","Promise","resolve","out","disabled","mode","map","index","rectProps","polyProps","circleProps","responseCorrect","undefined","extraCSSRules","role","rationale","rationaleEnabled","teacherInstructions","teacherInstructionsEnabled","promptEnabled","strokeWidth","createDefaultModel","getScore","config","answers","partialScoringEnabled","enabled","correctAnswers","selectedChoices","choices","correctChoices","filter","choice","correct","forEach","shape","selected","answer","id","correctlySelected","extraAnswers","length","total","str","toFixed","parseFloat","outcome","score","empty","returnShapesCorrect","i","push","createCorrectResponseSession","rectangleCorrect","polygonsCorrect","circlesCorrect","getInnerText","html","replaceAll","getContent","replace","validate","minShapes","maxShapes","maxSelections","errors","field","required","allShapes","Object","values","reduce","acc","nbOfSelections","nbOfShapes","selections"],"mappings":"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","sourcesContent":["import debug from 'debug';\nimport isEmpty from 'lodash/isEmpty';\nimport { partialScoring } from '@pie-lib/pie-toolbox/controller-utils';\n\nimport { isResponseCorrect } from './utils';\n\nimport defaults from './defaults';\n\nconst log = debug('pie-elements:hotspot:controller');\n\nexport const normalize = (question) => ({\n ...defaults,\n ...question,\n});\n\nexport function model(question, session, env) {\n const normalizedQuestion = normalize(question);\n const {\n imageUrl,\n dimensions,\n hotspotColor,\n hoverOutlineColor,\n selectedHotspotColor,\n multipleCorrect,\n outlineColor,\n partialScoring,\n prompt,\n shapes,\n language,\n fontSizeFactor,\n autoplayAudioEnabled,\n completeAudioEnabled\n } = normalizedQuestion;\n const { rectangles, polygons, circles } = shapes || {};\n\n return new Promise((resolve) => {\n const out = {\n disabled: env.mode !== 'gather',\n mode: env.mode,\n dimensions,\n imageUrl,\n outlineColor,\n hotspotColor,\n hoverOutlineColor,\n selectedHotspotColor,\n multipleCorrect,\n partialScoring,\n language,\n fontSizeFactor,\n autoplayAudioEnabled,\n completeAudioEnabled,\n shapes: {\n ...shapes,\n // eslint-disable-next-line no-unused-vars\n rectangles: (rectangles || []).map(({ index, ...rectProps }) => ({ ...rectProps })),\n // eslint-disable-next-line no-unused-vars\n polygons: (polygons || []).map(({ index, ...polyProps }) => ({ ...polyProps })),\n // eslint-disable-next-line no-unused-vars\n circles: (circles || []).map(({ index, ...circleProps }) => ({ ...circleProps })),\n },\n responseCorrect: env.mode === 'evaluate' ? isResponseCorrect(normalizedQuestion, session) : undefined,\n extraCSSRules: normalizedQuestion.extraCSSRules,\n };\n\n if (env.role === 'instructor' && (env.mode === 'view' || env.mode === 'evaluate')) {\n out.rationale = normalizedQuestion.rationaleEnabled ? normalizedQuestion.rationale : null;\n out.teacherInstructions = normalizedQuestion.teacherInstructionsEnabled\n ? normalizedQuestion.teacherInstructions\n : null;\n } else {\n out.rationale = null;\n out.teacherInstructions = null;\n }\n\n out.prompt = normalizedQuestion.promptEnabled ? prompt : null;\n out.strokeWidth = normalizedQuestion.strokeWidth;\n\n // console.log(out);\n resolve(out);\n });\n}\n\nexport const createDefaultModel = (model = {}) =>\n new Promise((resolve) => {\n resolve({\n ...defaults,\n ...model,\n });\n });\n\nconst getScore = (config, session, env = {}) => {\n const { answers } = session || {};\n\n if (!config.shapes || (!config.shapes.rectangles && !config.shapes.polygons && !config.shapes.circles)) {\n return 0;\n }\n\n const { shapes: { rectangles = [], polygons = [], circles = [] } = {} } = config;\n const partialScoringEnabled = partialScoring.enabled(config, env);\n\n if (!partialScoringEnabled) {\n return isResponseCorrect(config, session) ? 1 : 0;\n }\n\n let correctAnswers = 0;\n let selectedChoices = 0;\n\n const choices = [...rectangles, ...polygons, ...circles];\n\n const correctChoices = choices.filter((choice) => choice.correct);\n\n choices.forEach((shape) => {\n const selected = answers && answers.filter((answer) => answer.id === shape.id)[0];\n const correctlySelected = shape.correct && selected;\n\n if (selected) {\n selectedChoices += 1;\n }\n\n if (correctlySelected) {\n correctAnswers += 1;\n }\n });\n\n const extraAnswers = selectedChoices > correctChoices.length ? selectedChoices - correctChoices.length : 0;\n\n const total = correctChoices.length === 0 ? 1 : correctChoices.length;\n const str = ((correctAnswers - extraAnswers) / total).toFixed(2);\n\n return str < 0 ? 0 : parseFloat(str);\n};\n\nexport function outcome(config, session, env = {}) {\n return new Promise((resolve) => {\n log('outcome...');\n\n if (!session || isEmpty(session)) {\n resolve({ score: 0, empty: true });\n }\n\n if (session.answers) {\n const score = getScore(config, session, env);\n resolve({ score });\n } else {\n resolve({ score: 0, empty: true });\n }\n });\n}\n\nconst returnShapesCorrect = (shapes) => {\n let answers = [];\n\n shapes.forEach((i) => {\n const { correct, id } = i;\n if (correct) {\n answers.push({ id });\n }\n });\n return answers;\n};\n\nexport const createCorrectResponseSession = (question, env) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n const { shapes: { rectangles = [], circles = [], polygons = {} } = {} } = question;\n\n const rectangleCorrect = returnShapesCorrect(rectangles);\n const polygonsCorrect = returnShapesCorrect(polygons);\n const circlesCorrect = returnShapesCorrect(circles);\n\n resolve({\n answers: [...rectangleCorrect, ...polygonsCorrect, ...circlesCorrect],\n id: '1',\n });\n } else {\n resolve(null);\n }\n });\n};\n\n// remove all html tags\nconst getInnerText = (html) => (html || '').replaceAll(/<[^>]*>/g, '');\n\n// remove all html tags except img and iframe\nconst getContent = (html) => (html || '').replace(/(<(?!img|iframe)([^>]+)>)/gi, '');\n\nexport const validate = (model = {}, config = {}) => {\n const { shapes } = model;\n const { minShapes = 2, maxShapes, maxSelections } = config;\n const errors = {};\n\n ['teacherInstructions', 'prompt', 'rationale'].forEach((field) => {\n if (config[field]?.required && !getContent(model[field])) {\n errors[field] = 'This field is required.';\n }\n });\n\n const allShapes = Object.values(shapes || {}).reduce((acc, shape) => [...acc, ...shape], []);\n\n const nbOfSelections = (allShapes || []).reduce((acc, shape) => (shape.correct ? acc + 1 : acc), 0);\n\n const nbOfShapes = (allShapes || []).length;\n\n if (nbOfShapes < minShapes) {\n errors.shapes = `There should be at least ${minShapes} shapes defined.`;\n } else if (nbOfShapes > maxShapes) {\n errors.shapes = `No more than ${maxShapes} shapes should be defined.`;\n }\n\n if (nbOfSelections < 1) {\n errors.selections = 'There should be at least 1 shape selected.';\n } else if (nbOfSelections > maxSelections) {\n errors.selections = `No more than ${maxSelections} shapes should be selected.`;\n }\n\n return errors;\n};\n"],"file":"index.js"}
|
package/controller/src/index.js
CHANGED
|
@@ -28,6 +28,8 @@ export function model(question, session, env) {
|
|
|
28
28
|
shapes,
|
|
29
29
|
language,
|
|
30
30
|
fontSizeFactor,
|
|
31
|
+
autoplayAudioEnabled,
|
|
32
|
+
completeAudioEnabled
|
|
31
33
|
} = normalizedQuestion;
|
|
32
34
|
const { rectangles, polygons, circles } = shapes || {};
|
|
33
35
|
|
|
@@ -45,6 +47,8 @@ export function model(question, session, env) {
|
|
|
45
47
|
partialScoring,
|
|
46
48
|
language,
|
|
47
49
|
fontSizeFactor,
|
|
50
|
+
autoplayAudioEnabled,
|
|
51
|
+
completeAudioEnabled,
|
|
48
52
|
shapes: {
|
|
49
53
|
...shapes,
|
|
50
54
|
// eslint-disable-next-line no-unused-vars
|
package/docs/pie-schema.json
CHANGED
|
@@ -250,6 +250,16 @@
|
|
|
250
250
|
"type": "number",
|
|
251
251
|
"title": "fontSizeFactor"
|
|
252
252
|
},
|
|
253
|
+
"autoplayAudioEnabled": {
|
|
254
|
+
"description": "Indicates if the audio for the prompt should autoplay",
|
|
255
|
+
"type": "boolean",
|
|
256
|
+
"title": "autoplayAudioEnabled"
|
|
257
|
+
},
|
|
258
|
+
"completeAudioEnabled": {
|
|
259
|
+
"description": "Indicates if the audio should reach the end before the item can be marked as 'complete'",
|
|
260
|
+
"type": "boolean",
|
|
261
|
+
"title": "completeAudioEnabled"
|
|
262
|
+
},
|
|
253
263
|
"id": {
|
|
254
264
|
"description": "Identifier to identify the Pie Element in html markup, Must be unique within a pie item config.",
|
|
255
265
|
"type": "string",
|
package/docs/pie-schema.json.md
CHANGED
|
@@ -182,6 +182,14 @@ Supported options: en, es, en_US, en-US, es_ES, es-ES, es_MX, es-MX
|
|
|
182
182
|
|
|
183
183
|
Indicates font size adjustment factor
|
|
184
184
|
|
|
185
|
+
# `autoplayAudioEnabled` (boolean)
|
|
186
|
+
|
|
187
|
+
Indicates if the audio for the prompt should autoplay
|
|
188
|
+
|
|
189
|
+
# `completeAudioEnabled` (boolean)
|
|
190
|
+
|
|
191
|
+
Indicates if the audio should reach the end before the item can be marked as 'complete'
|
|
192
|
+
|
|
185
193
|
# `id` (string, required)
|
|
186
194
|
|
|
187
195
|
Identifier to identify the Pie Element in html markup, Must be unique within a pie item config.
|
package/lib/hotspot/index.js
CHANGED
|
@@ -130,11 +130,14 @@ var HotspotComponent = /*#__PURE__*/function (_React$Component) {
|
|
|
130
130
|
responseCorrect = _this$props$model.responseCorrect,
|
|
131
131
|
language = _this$props$model.language,
|
|
132
132
|
fontSizeFactor = _this$props$model.fontSizeFactor,
|
|
133
|
+
autoplayAudioEnabled = _this$props$model.autoplayAudioEnabled,
|
|
133
134
|
onSelectChoice = _this$props.onSelectChoice,
|
|
134
135
|
classes = _this$props.classes;
|
|
135
136
|
var showCorrect = this.state.showCorrect;
|
|
136
137
|
var isEvaluateMode = mode === 'evaluate';
|
|
137
|
-
var showCorrectAnswerToggle = isEvaluateMode && !responseCorrect;
|
|
138
|
+
var showCorrectAnswerToggle = isEvaluateMode && !responseCorrect; // Safari, Firefox, and Edge do not support autoplay audio smoothly in our use case
|
|
139
|
+
|
|
140
|
+
var addAutoplayAudio = autoplayAudioEnabled && !(/Safari|Firefox|Edg/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent));
|
|
138
141
|
return /*#__PURE__*/_react["default"].createElement(_renderUi.UiLayout, {
|
|
139
142
|
extraCSSRules: extraCSSRules,
|
|
140
143
|
className: classes.main,
|
|
@@ -150,7 +153,8 @@ var HotspotComponent = /*#__PURE__*/function (_React$Component) {
|
|
|
150
153
|
prompt: teacherInstructions
|
|
151
154
|
})), prompt && /*#__PURE__*/_react["default"].createElement(_renderUi.PreviewPrompt, {
|
|
152
155
|
className: "prompt",
|
|
153
|
-
prompt: prompt
|
|
156
|
+
prompt: prompt,
|
|
157
|
+
autoplayAudioEnabled: addAutoplayAudio
|
|
154
158
|
}), showCorrectAnswerToggle && /*#__PURE__*/_react["default"].createElement(_correctAnswerToggle.CorrectAnswerToggle, {
|
|
155
159
|
show: showCorrectAnswerToggle,
|
|
156
160
|
toggled: showCorrect,
|
|
@@ -200,7 +204,8 @@ var styles = function styles(theme) {
|
|
|
200
204
|
return {
|
|
201
205
|
main: {
|
|
202
206
|
color: _renderUi.color.text(),
|
|
203
|
-
backgroundColor: _renderUi.color.background()
|
|
207
|
+
backgroundColor: _renderUi.color.background(),
|
|
208
|
+
position: 'relative'
|
|
204
209
|
},
|
|
205
210
|
collapsible: {
|
|
206
211
|
marginBottom: theme.spacing.unit * 2
|
package/lib/hotspot/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hotspot/index.jsx"],"names":["HotspotComponent","props","showCorrect","state","setState","observer","scale","MutationObserver","mutations","forEach","target","document","getElementById","style","cssText","zoom","substring","indexOf","lastIndexOf","zoomParsed","replace","newScale","parseFloat","observe","attributes","attributeFilter","disconnect","session","model","disabled","extraCSSRules","imageUrl","prompt","mode","multipleCorrect","shapes","outlineColor","hotspotColor","hoverOutlineColor","selectedHotspotColor","dimensions","rationale","teacherInstructions","strokeWidth","responseCorrect","language","fontSizeFactor","onSelectChoice","classes","isEvaluateMode","showCorrectAnswerToggle","main","hidden","visible","collapsible","onToggle","bind","React","Component","propTypes","PropTypes","object","isRequired","func","defaultProps","styles","theme","color","text","backgroundColor","background","marginBottom","spacing","unit","fontSize"],"mappings":"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","sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { CorrectAnswerToggle } from '@pie-lib/pie-toolbox/correct-answer-toggle';\nimport { color, Collapsible, hasText, PreviewPrompt, UiLayout } from '@pie-lib/pie-toolbox/render-ui';\nimport { withStyles } from '@material-ui/core/styles';\n\nimport Container from './container';\n\nclass HotspotComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n showCorrect: false,\n observer: null,\n scale: 1,\n };\n }\n\n componentDidMount() {\n this.observer = new MutationObserver((mutations) => {\n mutations.forEach(() => {\n const target = document.getElementById('question-container')?.style?.cssText;\n const zoom = target?.substring(target.indexOf('--pie-zoom') + 11, target.lastIndexOf('%'));\n const zoomParsed = zoom?.replace(/\\s/g, '');\n\n if (zoomParsed) {\n const newScale = parseFloat(zoomParsed) / 100;\n\n if (newScale !== this.state.scale) {\n this.setState({\n scale: parseFloat(zoomParsed) / 100,\n });\n }\n } else if (!zoomParsed && this.state.scale !== 1) {\n this.setState({\n scale: 1,\n });\n }\n });\n });\n\n const target = document.getElementById('question-container');\n\n if (target) {\n this.observer.observe(target, { attributes: true, attributeFilter: ['style'] });\n }\n }\n\n componentWillUnmount() {\n this.observer?.disconnect();\n }\n\n onToggle = () => {\n const { showCorrect } = this.state;\n this.setState({ showCorrect: !showCorrect });\n };\n\n render() {\n const {\n session,\n model: {\n disabled,\n extraCSSRules,\n imageUrl,\n prompt,\n mode,\n multipleCorrect,\n shapes,\n outlineColor,\n hotspotColor,\n hoverOutlineColor,\n selectedHotspotColor,\n dimensions,\n rationale,\n teacherInstructions,\n strokeWidth,\n responseCorrect,\n language,\n fontSizeFactor,\n },\n onSelectChoice,\n classes,\n } = this.props;\n const { showCorrect } = this.state;\n const isEvaluateMode = mode === 'evaluate';\n const showCorrectAnswerToggle = isEvaluateMode && !responseCorrect;\n\n return (\n <UiLayout extraCSSRules={extraCSSRules} className={classes.main} fontSizeFactor={fontSizeFactor}>\n {teacherInstructions && hasText(teacherInstructions) && (\n <Collapsible\n labels={{ hidden: 'Show Teacher Instructions', visible: 'Hide Teacher Instructions' }}\n className={classes.collapsible}\n >\n <PreviewPrompt className=\"prompt\" prompt={teacherInstructions} />\n </Collapsible>\n )}\n\n {prompt && <PreviewPrompt className=\"prompt\" prompt={prompt} />}\n\n {showCorrectAnswerToggle && (\n <CorrectAnswerToggle\n show={showCorrectAnswerToggle}\n toggled={showCorrect}\n onToggle={this.onToggle.bind(this)}\n language={language}\n />\n )}\n\n {imageUrl ? (\n <Container\n isEvaluateMode={isEvaluateMode}\n session={session}\n dimensions={dimensions}\n imageUrl={imageUrl}\n hotspotColor={hotspotColor}\n hoverOutlineColor={hoverOutlineColor}\n selectedHotspotColor={selectedHotspotColor}\n multipleCorrect={multipleCorrect}\n outlineColor={outlineColor}\n onSelectChoice={onSelectChoice}\n shapes={shapes}\n disabled={disabled}\n strokeWidth={strokeWidth}\n scale={this.state.scale}\n showCorrect={showCorrect}\n />\n ) : null}\n\n {rationale && hasText(rationale) && (\n <Collapsible labels={{ hidden: 'Show Rationale', visible: 'Hide Rationale' }}>\n <PreviewPrompt className=\"prompt\" prompt={rationale} />\n </Collapsible>\n )}\n </UiLayout>\n );\n }\n}\n\nHotspotComponent.propTypes = {\n classes: PropTypes.object,\n model: PropTypes.object.isRequired,\n onSelectChoice: PropTypes.func.isRequired,\n session: PropTypes.object.isRequired,\n};\n\nHotspotComponent.defaultProps = {\n classes: {},\n};\n\nconst styles = (theme) => ({\n main: {\n color: color.text(),\n backgroundColor: color.background(),\n },\n collapsible: {\n marginBottom: theme.spacing.unit * 2,\n },\n prompt: {\n fontSize: 'inherit',\n },\n});\n\nexport default withStyles(styles)(HotspotComponent);\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../../src/hotspot/index.jsx"],"names":["HotspotComponent","props","showCorrect","state","setState","observer","scale","MutationObserver","mutations","forEach","target","document","getElementById","style","cssText","zoom","substring","indexOf","lastIndexOf","zoomParsed","replace","newScale","parseFloat","observe","attributes","attributeFilter","disconnect","session","model","disabled","extraCSSRules","imageUrl","prompt","mode","multipleCorrect","shapes","outlineColor","hotspotColor","hoverOutlineColor","selectedHotspotColor","dimensions","rationale","teacherInstructions","strokeWidth","responseCorrect","language","fontSizeFactor","autoplayAudioEnabled","onSelectChoice","classes","isEvaluateMode","showCorrectAnswerToggle","addAutoplayAudio","test","navigator","userAgent","main","hidden","visible","collapsible","onToggle","bind","React","Component","propTypes","PropTypes","object","isRequired","func","defaultProps","styles","theme","color","text","backgroundColor","background","position","marginBottom","spacing","unit","fontSize"],"mappings":"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","sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { CorrectAnswerToggle } from '@pie-lib/pie-toolbox/correct-answer-toggle';\nimport { color, Collapsible, hasText, PreviewPrompt, UiLayout } from '@pie-lib/pie-toolbox/render-ui';\nimport { withStyles } from '@material-ui/core/styles';\n\nimport Container from './container';\n\nclass HotspotComponent extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n showCorrect: false,\n observer: null,\n scale: 1,\n };\n }\n\n componentDidMount() {\n this.observer = new MutationObserver((mutations) => {\n mutations.forEach(() => {\n const target = document.getElementById('question-container')?.style?.cssText;\n const zoom = target?.substring(target.indexOf('--pie-zoom') + 11, target.lastIndexOf('%'));\n const zoomParsed = zoom?.replace(/\\s/g, '');\n\n if (zoomParsed) {\n const newScale = parseFloat(zoomParsed) / 100;\n\n if (newScale !== this.state.scale) {\n this.setState({\n scale: parseFloat(zoomParsed) / 100,\n });\n }\n } else if (!zoomParsed && this.state.scale !== 1) {\n this.setState({\n scale: 1,\n });\n }\n });\n });\n\n const target = document.getElementById('question-container');\n\n if (target) {\n this.observer.observe(target, { attributes: true, attributeFilter: ['style'] });\n }\n }\n\n componentWillUnmount() {\n this.observer?.disconnect();\n }\n\n onToggle = () => {\n const { showCorrect } = this.state;\n this.setState({ showCorrect: !showCorrect });\n };\n\n render() {\n const {\n session,\n model: {\n disabled,\n extraCSSRules,\n imageUrl,\n prompt,\n mode,\n multipleCorrect,\n shapes,\n outlineColor,\n hotspotColor,\n hoverOutlineColor,\n selectedHotspotColor,\n dimensions,\n rationale,\n teacherInstructions,\n strokeWidth,\n responseCorrect,\n language,\n fontSizeFactor,\n autoplayAudioEnabled\n },\n onSelectChoice,\n classes,\n } = this.props;\n const { showCorrect } = this.state;\n const isEvaluateMode = mode === 'evaluate';\n const showCorrectAnswerToggle = isEvaluateMode && !responseCorrect;\n // Safari, Firefox, and Edge do not support autoplay audio smoothly in our use case\n const addAutoplayAudio = autoplayAudioEnabled && !(/Safari|Firefox|Edg/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent));\n\n return (\n <UiLayout extraCSSRules={extraCSSRules} className={classes.main} fontSizeFactor={fontSizeFactor}>\n {teacherInstructions && hasText(teacherInstructions) && (\n <Collapsible\n labels={{ hidden: 'Show Teacher Instructions', visible: 'Hide Teacher Instructions' }}\n className={classes.collapsible}\n >\n <PreviewPrompt className=\"prompt\" prompt={teacherInstructions} />\n </Collapsible>\n )}\n\n {prompt && <PreviewPrompt className=\"prompt\" prompt={prompt} autoplayAudioEnabled={addAutoplayAudio} />}\n\n {showCorrectAnswerToggle && (\n <CorrectAnswerToggle\n show={showCorrectAnswerToggle}\n toggled={showCorrect}\n onToggle={this.onToggle.bind(this)}\n language={language}\n />\n )}\n\n {imageUrl ? (\n <Container\n isEvaluateMode={isEvaluateMode}\n session={session}\n dimensions={dimensions}\n imageUrl={imageUrl}\n hotspotColor={hotspotColor}\n hoverOutlineColor={hoverOutlineColor}\n selectedHotspotColor={selectedHotspotColor}\n multipleCorrect={multipleCorrect}\n outlineColor={outlineColor}\n onSelectChoice={onSelectChoice}\n shapes={shapes}\n disabled={disabled}\n strokeWidth={strokeWidth}\n scale={this.state.scale}\n showCorrect={showCorrect}\n />\n ) : null}\n\n {rationale && hasText(rationale) && (\n <Collapsible labels={{ hidden: 'Show Rationale', visible: 'Hide Rationale' }}>\n <PreviewPrompt className=\"prompt\" prompt={rationale} />\n </Collapsible>\n )}\n </UiLayout>\n );\n }\n}\n\nHotspotComponent.propTypes = {\n classes: PropTypes.object,\n model: PropTypes.object.isRequired,\n onSelectChoice: PropTypes.func.isRequired,\n session: PropTypes.object.isRequired,\n};\n\nHotspotComponent.defaultProps = {\n classes: {},\n};\n\nconst styles = (theme) => ({\n main: {\n color: color.text(),\n backgroundColor: color.background(),\n position: 'relative'\n },\n collapsible: {\n marginBottom: theme.spacing.unit * 2,\n },\n prompt: {\n fontSize: 'inherit',\n },\n});\n\nexport default withStyles(styles)(HotspotComponent);\n"],"file":"index.js"}
|
package/lib/index.js
CHANGED
|
@@ -41,8 +41,14 @@ var Hotspot = /*#__PURE__*/function (_HTMLElement) {
|
|
|
41
41
|
var _super = _createSuper(Hotspot);
|
|
42
42
|
|
|
43
43
|
function Hotspot() {
|
|
44
|
+
var _this;
|
|
45
|
+
|
|
44
46
|
(0, _classCallCheck2["default"])(this, Hotspot);
|
|
45
|
-
|
|
47
|
+
_this = _super.call(this);
|
|
48
|
+
_this._model = null;
|
|
49
|
+
_this._session = null;
|
|
50
|
+
_this.audioComplete = false;
|
|
51
|
+
return _this;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
(0, _createClass2["default"])(Hotspot, [{
|
|
@@ -60,6 +66,14 @@ var Hotspot = /*#__PURE__*/function (_HTMLElement) {
|
|
|
60
66
|
return false;
|
|
61
67
|
}
|
|
62
68
|
|
|
69
|
+
var _ref = this._model || {},
|
|
70
|
+
autoplayAudioEnabled = _ref.autoplayAudioEnabled,
|
|
71
|
+
completeAudioEnabled = _ref.completeAudioEnabled;
|
|
72
|
+
|
|
73
|
+
if (autoplayAudioEnabled && completeAudioEnabled && !this.audioComplete) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
63
77
|
if (!Array.isArray(this._session.answers)) {
|
|
64
78
|
return false;
|
|
65
79
|
}
|
|
@@ -88,15 +102,112 @@ var Hotspot = /*#__PURE__*/function (_HTMLElement) {
|
|
|
88
102
|
|
|
89
103
|
this._render();
|
|
90
104
|
}
|
|
105
|
+
}, {
|
|
106
|
+
key: "_createAudioInfoToast",
|
|
107
|
+
value: function _createAudioInfoToast() {
|
|
108
|
+
var info = document.createElement('div');
|
|
109
|
+
info.id = 'play-audio-info';
|
|
110
|
+
Object.assign(info.style, {
|
|
111
|
+
position: 'absolute',
|
|
112
|
+
top: 0,
|
|
113
|
+
width: '100%',
|
|
114
|
+
height: '100%',
|
|
115
|
+
display: 'flex',
|
|
116
|
+
justifyContent: 'center',
|
|
117
|
+
alignItems: 'center',
|
|
118
|
+
background: 'white',
|
|
119
|
+
zIndex: '1000'
|
|
120
|
+
});
|
|
121
|
+
var img = document.createElement('img');
|
|
122
|
+
img.src = 'https://student.assessment.renaissance.com/ce/quizenginecap/assets/img/playAppsSel.gif';
|
|
123
|
+
img.alt = 'Click anywhere to enable audio autoplay';
|
|
124
|
+
img.width = 500;
|
|
125
|
+
img.height = 300;
|
|
126
|
+
info.appendChild(img);
|
|
127
|
+
return info;
|
|
128
|
+
}
|
|
91
129
|
}, {
|
|
92
130
|
key: "connectedCallback",
|
|
93
131
|
value: function connectedCallback() {
|
|
132
|
+
var _this2 = this;
|
|
133
|
+
|
|
94
134
|
this._render();
|
|
135
|
+
|
|
136
|
+
if (this._model && !this._model.autoplayAudioEnabled) {
|
|
137
|
+
return;
|
|
138
|
+
} // Observation: audio in Chrome will have the autoplay attribute,
|
|
139
|
+
// while other browsers will not have the autoplay attribute and will need a user interaction to play the audio
|
|
140
|
+
// This workaround fixes the issue of audio being cached and played on any user interaction in Safari and Firefox
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
var observer = new MutationObserver(function (mutationsList, observer) {
|
|
144
|
+
mutationsList.forEach(function (mutation) {
|
|
145
|
+
if (mutation.type === 'childList') {
|
|
146
|
+
var audio = _this2.querySelector('audio');
|
|
147
|
+
|
|
148
|
+
var isInsidePrompt = audio && audio.closest('#preview-prompt');
|
|
149
|
+
if (audio && !isInsidePrompt) return;
|
|
150
|
+
if (!audio) return;
|
|
151
|
+
|
|
152
|
+
var info = _this2._createAudioInfoToast();
|
|
153
|
+
|
|
154
|
+
var container = _this2.querySelector('[class*="main"]');
|
|
155
|
+
|
|
156
|
+
var enableAudio = function enableAudio() {
|
|
157
|
+
if (_this2.querySelector('#play-audio-info')) {
|
|
158
|
+
audio.play();
|
|
159
|
+
container.removeChild(info);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
document.removeEventListener('click', enableAudio);
|
|
163
|
+
}; // if the audio is paused, it means the user has not interacted with the page yet and the audio will not play
|
|
164
|
+
// FIX FOR SAFARI: play with a slight delay to check if autoplay was blocked
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
setTimeout(function () {
|
|
168
|
+
if (audio.paused && !_this2.querySelector('#play-audio-info')) {
|
|
169
|
+
// add info message as a toast to enable audio playback
|
|
170
|
+
container.appendChild(info);
|
|
171
|
+
document.addEventListener('click', enableAudio);
|
|
172
|
+
} else {
|
|
173
|
+
document.removeEventListener('click', enableAudio);
|
|
174
|
+
}
|
|
175
|
+
}, 500); // we need to listen for the playing event to remove the toast in case the audio plays because of re-rendering
|
|
176
|
+
|
|
177
|
+
var handlePlaying = function handlePlaying() {
|
|
178
|
+
var info = _this2.querySelector('#play-audio-info');
|
|
179
|
+
|
|
180
|
+
if (info) {
|
|
181
|
+
_this2.removeChild(info);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
audio.removeEventListener('playing', handlePlaying);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
audio.addEventListener('playing', handlePlaying); // we need to listen for the ended event to update the isComplete state
|
|
188
|
+
|
|
189
|
+
var handleEnded = function handleEnded() {
|
|
190
|
+
_this2.audioComplete = true;
|
|
191
|
+
|
|
192
|
+
_this2.dispatchEvent(new _piePlayerEvents.SessionChangedEvent(_this2.tagName.toLowerCase(), _this2.isComplete()));
|
|
193
|
+
|
|
194
|
+
audio.removeEventListener('ended', handleEnded);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
audio.addEventListener('ended', handleEnded);
|
|
198
|
+
observer.disconnect();
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
observer.observe(this, {
|
|
203
|
+
childList: true,
|
|
204
|
+
subtree: true
|
|
205
|
+
});
|
|
95
206
|
}
|
|
96
207
|
}, {
|
|
97
208
|
key: "_render",
|
|
98
209
|
value: function _render() {
|
|
99
|
-
var
|
|
210
|
+
var _this3 = this;
|
|
100
211
|
|
|
101
212
|
if (this._model && this._session) {
|
|
102
213
|
var el = /*#__PURE__*/_react["default"].createElement(_hotspot["default"], {
|
|
@@ -106,7 +217,7 @@ var Hotspot = /*#__PURE__*/function (_HTMLElement) {
|
|
|
106
217
|
});
|
|
107
218
|
|
|
108
219
|
_reactDom["default"].render(el, this, function () {
|
|
109
|
-
(0, _mathRendering.renderMath)(
|
|
220
|
+
(0, _mathRendering.renderMath)(_this3);
|
|
110
221
|
});
|
|
111
222
|
}
|
|
112
223
|
}
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.js"],"names":["Hotspot","m","_model","dispatchEvent","ModelSetEvent","tagName","toLowerCase","isComplete","_render","_session","answers","Array","isArray","length","s","data","SessionChangedEvent","el","React","createElement","HotspotComponent","model","session","onSelectChoice","bind","ReactDOM","render","HTMLElement"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;AACA;;AACA;;AAEA;;AACA;;;;;;IAEqBA,O;;;;;;;;;;;;SACnB,aAAUC,CAAV,EAAa;AACX,WAAKC,MAAL,GAAcD,CAAd;AAEA,WAAKE,aAAL,CAAmB,IAAIC,8BAAJ,CAAkB,KAAKC,OAAL,CAAaC,WAAb,EAAlB,EAA8C,KAAKC,UAAL,EAA9C,EAAiE,CAAC,CAAC,KAAKL,MAAxE,CAAnB;;AACA,WAAKM,OAAL;AACD;;;WAED,sBAAa;AACX,UAAI,CAAC,KAAKC,QAAN,IAAkB,CAAC,KAAKA,QAAL,CAAcC,OAArC,EAA8C;AAC5C,eAAO,KAAP;AACD;;AAED,UAAI,CAACC,KAAK,CAACC,OAAN,CAAc,KAAKH,QAAL,CAAcC,OAA5B,CAAL,EAA2C;AACzC,eAAO,KAAP;AACD;;AAED,aAAO,KAAKD,QAAL,CAAcC,OAAd,CAAsBG,MAAtB,GAA+B,CAAtC;AACD;;;SAWD,eAAc;AACZ,aAAO,KAAKJ,QAAZ;AACD,K;SAXD,aAAYK,CAAZ,EAAe;AACb,UAAIA,CAAC,IAAI,CAACA,CAAC,CAACJ,OAAZ,EAAqB;AACnBI,QAAAA,CAAC,CAACJ,OAAF,GAAY,EAAZ;AACD;;AAED,WAAKD,QAAL,GAAgBK,CAAhB;;AACA,WAAKN,OAAL;AACD;;;WAMD,wBAAeO,IAAf,EAAqB;AACnB,8CAAmB,KAAKN,QAAxB,EAAkC,KAAKP,MAAvC,EAA+Ca,IAA/C;AAEA,WAAKZ,aAAL,CAAmB,IAAIa,oCAAJ,CAAwB,KAAKX,OAAL,CAAaC,WAAb,EAAxB,EAAoD,KAAKC,UAAL,EAApD,CAAnB;;AAEA,WAAKC,OAAL;AACD;;;WAED,6BAAoB;AAClB,WAAKA,OAAL;AACD;;;WAED,mBAAU;AAAA;;AACR,UAAI,KAAKN,MAAL,IAAe,KAAKO,QAAxB,EAAkC;AAChC,YAAMQ,EAAE,gBAAGC,kBAAMC,aAAN,CAAoBC,mBAApB,EAAsC;AAC/CC,UAAAA,KAAK,EAAE,KAAKnB,MADmC;AAE/CoB,UAAAA,OAAO,EAAE,KAAKb,QAFiC;AAG/Cc,UAAAA,cAAc,EAAE,KAAKA,cAAL,CAAoBC,IAApB,CAAyB,IAAzB;AAH+B,SAAtC,CAAX;;AAMAC,6BAASC,MAAT,CAAgBT,EAAhB,EAAoB,IAApB,EAA0B,YAAM;AAC9B,yCAAW,KAAX;AACD,SAFD;AAGD;AACF;;;kDAzDkCU,W","sourcesContent":["import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { renderMath } from '@pie-lib/pie-toolbox/math-rendering';\nimport { SessionChangedEvent, ModelSetEvent } from '@pie-framework/pie-player-events';\n\nimport HotspotComponent from './hotspot';\nimport { updateSessionValue } from './session-updater';\n\nexport default class Hotspot extends HTMLElement {\n set model(m) {\n this._model = m;\n\n this.dispatchEvent(new ModelSetEvent(this.tagName.toLowerCase(), this.isComplete(), !!this._model));\n this._render();\n }\n\n isComplete() {\n if (!this._session || !this._session.answers) {\n return false;\n }\n\n if (!Array.isArray(this._session.answers)) {\n return false;\n }\n\n return this._session.answers.length > 0;\n }\n\n set session(s) {\n if (s && !s.answers) {\n s.answers = [];\n }\n\n this._session = s;\n this._render();\n }\n\n get session() {\n return this._session;\n }\n\n onSelectChoice(data) {\n updateSessionValue(this._session, this._model, data);\n\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));\n\n this._render();\n }\n\n connectedCallback() {\n this._render();\n }\n\n _render() {\n if (this._model && this._session) {\n const el = React.createElement(HotspotComponent, {\n model: this._model,\n session: this._session,\n onSelectChoice: this.onSelectChoice.bind(this),\n });\n\n ReactDOM.render(el, this, () => {\n renderMath(this);\n });\n }\n }\n}\n"],"file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/index.js"],"names":["Hotspot","_model","_session","audioComplete","m","dispatchEvent","ModelSetEvent","tagName","toLowerCase","isComplete","_render","answers","autoplayAudioEnabled","completeAudioEnabled","Array","isArray","length","s","data","SessionChangedEvent","info","document","createElement","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","handleEnded","disconnect","observe","childList","subtree","el","React","HotspotComponent","model","session","onSelectChoice","bind","ReactDOM","render","HTMLElement"],"mappings":"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","sourcesContent":["import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { renderMath } from '@pie-lib/pie-toolbox/math-rendering';\nimport { SessionChangedEvent, ModelSetEvent } from '@pie-framework/pie-player-events';\n\nimport HotspotComponent from './hotspot';\nimport { updateSessionValue } from './session-updater';\n\nexport default class Hotspot extends HTMLElement {\n constructor() {\n super();\n this._model = null;\n this._session = null;\n this.audioComplete = false;\n }\n\n set model(m) {\n this._model = m;\n\n this.dispatchEvent(new ModelSetEvent(this.tagName.toLowerCase(), this.isComplete(), !!this._model));\n this._render();\n }\n\n isComplete() {\n if (!this._session || !this._session.answers) {\n return false;\n }\n\n const { autoplayAudioEnabled, completeAudioEnabled } = this._model || {};\n if (autoplayAudioEnabled && completeAudioEnabled && !this.audioComplete) {\n return false;\n }\n\n if (!Array.isArray(this._session.answers)) {\n return false;\n }\n\n return this._session.answers.length > 0;\n }\n\n set session(s) {\n if (s && !s.answers) {\n s.answers = [];\n }\n\n this._session = s;\n this._render();\n }\n\n get session() {\n return this._session;\n }\n\n onSelectChoice(data) {\n updateSessionValue(this._session, this._model, data);\n\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));\n\n this._render();\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._render();\n\n if (this._model && !this._model.autoplayAudioEnabled) {\n return;\n }\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 (audio && !isInsidePrompt) return;\n if (!audio) return;\n\n const info = this._createAudioInfoToast();\n const container = this.querySelector('[class*=\"main\"]');\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 const info = this.querySelector('#play-audio-info');\n\n if (info) {\n this.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 this.audioComplete = true;\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));\n\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 _render() {\n if (this._model && this._session) {\n const el = React.createElement(HotspotComponent, {\n model: this._model,\n session: this._session,\n onSelectChoice: this.onSelectChoice.bind(this),\n });\n\n ReactDOM.render(el, this, () => {\n renderMath(this);\n });\n }\n }\n}\n"],"file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-element/hotspot",
|
|
3
|
-
"version": "7.5.3-next.
|
|
3
|
+
"version": "7.5.3-next.25+79e53d966",
|
|
4
4
|
"description": "",
|
|
5
5
|
"repository": "pie-framework/pie-elements",
|
|
6
6
|
"publishConfig": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"author": "pie framework developers",
|
|
20
20
|
"license": "ISC",
|
|
21
|
-
"gitHead": "
|
|
21
|
+
"gitHead": "79e53d966c02d724e1cb4e48609ff52891a9c705",
|
|
22
22
|
"scripts": {
|
|
23
23
|
"postpublish": "../../scripts/postpublish"
|
|
24
24
|
},
|
package/src/hotspot/index.jsx
CHANGED
|
@@ -77,6 +77,7 @@ class HotspotComponent extends React.Component {
|
|
|
77
77
|
responseCorrect,
|
|
78
78
|
language,
|
|
79
79
|
fontSizeFactor,
|
|
80
|
+
autoplayAudioEnabled
|
|
80
81
|
},
|
|
81
82
|
onSelectChoice,
|
|
82
83
|
classes,
|
|
@@ -84,6 +85,8 @@ class HotspotComponent extends React.Component {
|
|
|
84
85
|
const { showCorrect } = this.state;
|
|
85
86
|
const isEvaluateMode = mode === 'evaluate';
|
|
86
87
|
const showCorrectAnswerToggle = isEvaluateMode && !responseCorrect;
|
|
88
|
+
// Safari, Firefox, and Edge do not support autoplay audio smoothly in our use case
|
|
89
|
+
const addAutoplayAudio = autoplayAudioEnabled && !(/Safari|Firefox|Edg/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent));
|
|
87
90
|
|
|
88
91
|
return (
|
|
89
92
|
<UiLayout extraCSSRules={extraCSSRules} className={classes.main} fontSizeFactor={fontSizeFactor}>
|
|
@@ -96,7 +99,7 @@ class HotspotComponent extends React.Component {
|
|
|
96
99
|
</Collapsible>
|
|
97
100
|
)}
|
|
98
101
|
|
|
99
|
-
{prompt && <PreviewPrompt className="prompt" prompt={prompt} />}
|
|
102
|
+
{prompt && <PreviewPrompt className="prompt" prompt={prompt} autoplayAudioEnabled={addAutoplayAudio} />}
|
|
100
103
|
|
|
101
104
|
{showCorrectAnswerToggle && (
|
|
102
105
|
<CorrectAnswerToggle
|
|
@@ -152,6 +155,7 @@ const styles = (theme) => ({
|
|
|
152
155
|
main: {
|
|
153
156
|
color: color.text(),
|
|
154
157
|
backgroundColor: color.background(),
|
|
158
|
+
position: 'relative'
|
|
155
159
|
},
|
|
156
160
|
collapsible: {
|
|
157
161
|
marginBottom: theme.spacing.unit * 2,
|
package/src/index.js
CHANGED
|
@@ -7,7 +7,14 @@ import HotspotComponent from './hotspot';
|
|
|
7
7
|
import { updateSessionValue } from './session-updater';
|
|
8
8
|
|
|
9
9
|
export default class Hotspot extends HTMLElement {
|
|
10
|
-
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this._model = null;
|
|
13
|
+
this._session = null;
|
|
14
|
+
this.audioComplete = false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set model(m) {
|
|
11
18
|
this._model = m;
|
|
12
19
|
|
|
13
20
|
this.dispatchEvent(new ModelSetEvent(this.tagName.toLowerCase(), this.isComplete(), !!this._model));
|
|
@@ -19,6 +26,11 @@ export default class Hotspot extends HTMLElement {
|
|
|
19
26
|
return false;
|
|
20
27
|
}
|
|
21
28
|
|
|
29
|
+
const { autoplayAudioEnabled, completeAudioEnabled } = this._model || {};
|
|
30
|
+
if (autoplayAudioEnabled && completeAudioEnabled && !this.audioComplete) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
if (!Array.isArray(this._session.answers)) {
|
|
23
35
|
return false;
|
|
24
36
|
}
|
|
@@ -47,8 +59,103 @@ export default class Hotspot extends HTMLElement {
|
|
|
47
59
|
this._render();
|
|
48
60
|
}
|
|
49
61
|
|
|
62
|
+
_createAudioInfoToast() {
|
|
63
|
+
const info = document.createElement('div');
|
|
64
|
+
info.id = 'play-audio-info';
|
|
65
|
+
|
|
66
|
+
Object.assign(info.style, {
|
|
67
|
+
position: 'absolute',
|
|
68
|
+
top: 0,
|
|
69
|
+
width:'100%',
|
|
70
|
+
height: '100%',
|
|
71
|
+
display: 'flex',
|
|
72
|
+
justifyContent: 'center',
|
|
73
|
+
alignItems: 'center',
|
|
74
|
+
background: 'white',
|
|
75
|
+
zIndex: '1000'
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const img = document.createElement('img');
|
|
79
|
+
img.src = 'https://student.assessment.renaissance.com/ce/quizenginecap/assets/img/playAppsSel.gif';
|
|
80
|
+
img.alt = 'Click anywhere to enable audio autoplay';
|
|
81
|
+
img.width = 500;
|
|
82
|
+
img.height = 300;
|
|
83
|
+
|
|
84
|
+
info.appendChild(img);
|
|
85
|
+
return info;
|
|
86
|
+
}
|
|
87
|
+
|
|
50
88
|
connectedCallback() {
|
|
51
89
|
this._render();
|
|
90
|
+
|
|
91
|
+
if (this._model && !this._model.autoplayAudioEnabled) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Observation: audio in Chrome will have the autoplay attribute,
|
|
96
|
+
// while other browsers will not have the autoplay attribute and will need a user interaction to play the audio
|
|
97
|
+
// This workaround fixes the issue of audio being cached and played on any user interaction in Safari and Firefox
|
|
98
|
+
const observer = new MutationObserver((mutationsList, observer) => {
|
|
99
|
+
mutationsList.forEach((mutation) => {
|
|
100
|
+
if (mutation.type === 'childList') {
|
|
101
|
+
const audio = this.querySelector('audio');
|
|
102
|
+
const isInsidePrompt = audio && audio.closest('#preview-prompt');
|
|
103
|
+
|
|
104
|
+
if (audio && !isInsidePrompt) return;
|
|
105
|
+
if (!audio) return;
|
|
106
|
+
|
|
107
|
+
const info = this._createAudioInfoToast();
|
|
108
|
+
const container = this.querySelector('[class*="main"]');
|
|
109
|
+
const enableAudio = () => {
|
|
110
|
+
if (this.querySelector('#play-audio-info')) {
|
|
111
|
+
audio.play();
|
|
112
|
+
container.removeChild(info);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
document.removeEventListener('click', enableAudio);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// if the audio is paused, it means the user has not interacted with the page yet and the audio will not play
|
|
119
|
+
// FIX FOR SAFARI: play with a slight delay to check if autoplay was blocked
|
|
120
|
+
setTimeout(() => {
|
|
121
|
+
if (audio.paused && !this.querySelector('#play-audio-info')) {
|
|
122
|
+
// add info message as a toast to enable audio playback
|
|
123
|
+
container.appendChild(info);
|
|
124
|
+
document.addEventListener('click', enableAudio);
|
|
125
|
+
} else {
|
|
126
|
+
document.removeEventListener('click', enableAudio);
|
|
127
|
+
}
|
|
128
|
+
}, 500);
|
|
129
|
+
|
|
130
|
+
// we need to listen for the playing event to remove the toast in case the audio plays because of re-rendering
|
|
131
|
+
const handlePlaying = () => {
|
|
132
|
+
const info = this.querySelector('#play-audio-info');
|
|
133
|
+
|
|
134
|
+
if (info) {
|
|
135
|
+
this.removeChild(info);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
audio.removeEventListener('playing', handlePlaying);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
audio.addEventListener('playing', handlePlaying);
|
|
142
|
+
|
|
143
|
+
// we need to listen for the ended event to update the isComplete state
|
|
144
|
+
const handleEnded = () => {
|
|
145
|
+
this.audioComplete = true;
|
|
146
|
+
this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));
|
|
147
|
+
|
|
148
|
+
audio.removeEventListener('ended', handleEnded);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
audio.addEventListener('ended', handleEnded);
|
|
152
|
+
|
|
153
|
+
observer.disconnect();
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
observer.observe(this, { childList: true, subtree: true });
|
|
52
159
|
}
|
|
53
160
|
|
|
54
161
|
_render() {
|