jclic 2.2.0 → 2.3.0
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/README.md +5 -7
- package/dist-node/jclic-node.js +14157 -0
- package/dist-node/jclic-node.umd.cjs +530 -0
- package/package.json +38 -26
- package/.vscode/launch.json +0 -33
- package/.vscode/settings.json +0 -13
- package/CHANGELOG.md +0 -664
- package/TRANSLATIONS.md +0 -11
- package/build-locales.mjs +0 -82
- package/dist/jclic-node.js +0 -31678
- package/dist/jclic-node.js.map +0 -1
- package/dist/jclic.components.LICENSE +0 -2254
- package/dist/jclic.min.js +0 -27
- package/dist/jclic.min.js.map +0 -1
- package/eslint.config.mjs +0 -31
- package/jsdoc.config.js +0 -71
- package/locales/ar.po +0 -244
- package/locales/ast.po +0 -246
- package/locales/bs.po +0 -247
- package/locales/ca.po +0 -248
- package/locales/ca_ES@valencia.po +0 -248
- package/locales/cs.po +0 -244
- package/locales/da.po +0 -244
- package/locales/de.po +0 -246
- package/locales/el.po +0 -244
- package/locales/es.po +0 -248
- package/locales/eu.po +0 -244
- package/locales/fr.po +0 -244
- package/locales/gl.po +0 -244
- package/locales/he.po +0 -244
- package/locales/hr.po +0 -245
- package/locales/it.po +0 -246
- package/locales/ja.po +0 -242
- package/locales/jclic.js.pot +0 -241
- package/locales/nb_NO.po +0 -244
- package/locales/nl.po +0 -244
- package/locales/pl.po +0 -244
- package/locales/pt.po +0 -244
- package/locales/pt_BR.po +0 -248
- package/locales/ro.po +0 -248
- package/locales/ru.po +0 -245
- package/locales/ta.po +0 -244
- package/locales/tr.po +0 -246
- package/locales/uk.po +0 -247
- package/locales/vec.po +0 -244
- package/locales/zh_TW.po +0 -246
- package/patches/po2json+1.0.0-beta-3.patch +0 -12
- package/src/AWT.js +0 -2067
- package/src/Activity.js +0 -1311
- package/src/Deps.js +0 -232
- package/src/GlobalData.js +0 -5
- package/src/JClic.js +0 -196
- package/src/JClicPlayer.js +0 -1308
- package/src/PlayerHistory.js +0 -305
- package/src/Utils.js +0 -1355
- package/src/activities/associations/ComplexAssociation.js +0 -321
- package/src/activities/associations/SimpleAssociation.js +0 -519
- package/src/activities/memory/MemoryGame.js +0 -423
- package/src/activities/panels/Explore.js +0 -349
- package/src/activities/panels/Identify.js +0 -356
- package/src/activities/panels/InformationScreen.js +0 -262
- package/src/activities/panels/Menu.js +0 -209
- package/src/activities/panels/icons/ico00.png +0 -0
- package/src/activities/panels/icons/ico01.png +0 -0
- package/src/activities/panels/icons/ico02.png +0 -0
- package/src/activities/panels/icons/ico03.png +0 -0
- package/src/activities/panels/icons/icofolder.png +0 -0
- package/src/activities/puzzles/DoublePuzzle.js +0 -424
- package/src/activities/puzzles/ExchangePuzzle.js +0 -374
- package/src/activities/puzzles/HolePuzzle.js +0 -360
- package/src/activities/text/Complete.js +0 -127
- package/src/activities/text/Evaluator.js +0 -534
- package/src/activities/text/FillInBlanks.js +0 -426
- package/src/activities/text/IdentifyText.js +0 -253
- package/src/activities/text/OrderText.js +0 -421
- package/src/activities/text/TextActivityBase.js +0 -557
- package/src/activities/text/TextActivityDocument.js +0 -658
- package/src/activities/text/WrittenAnswer.js +0 -557
- package/src/activities/textGrid/CrossWord.js +0 -565
- package/src/activities/textGrid/WordSearch.js +0 -458
- package/src/activities/textGrid/icons/hIcon.svg +0 -3
- package/src/activities/textGrid/icons/vIcon.svg +0 -3
- package/src/automation/AutoContentProvider.js +0 -182
- package/src/automation/arith/Arith.js +0 -864
- package/src/bags/ActivitySequence.js +0 -318
- package/src/bags/ActivitySequenceElement.js +0 -161
- package/src/bags/ActivitySequenceJump.js +0 -140
- package/src/bags/ConditionalJumpInfo.js +0 -113
- package/src/bags/JumpInfo.js +0 -136
- package/src/bags/MediaBag.js +0 -215
- package/src/bags/MediaBagElement.js +0 -516
- package/src/boxes/AbstractBox.js +0 -699
- package/src/boxes/ActiveBagContent.js +0 -494
- package/src/boxes/ActiveBox.js +0 -810
- package/src/boxes/ActiveBoxBag.js +0 -357
- package/src/boxes/ActiveBoxContent.js +0 -484
- package/src/boxes/ActiveBoxGrid.js +0 -179
- package/src/boxes/BoxBag.js +0 -500
- package/src/boxes/BoxBase.js +0 -398
- package/src/boxes/BoxConnector.js +0 -325
- package/src/boxes/TextGrid.js +0 -887
- package/src/boxes/TextGridContent.js +0 -215
- package/src/init-jsdom.js +0 -65
- package/src/jclic-node.js +0 -219
- package/src/media/ActiveMediaBag.js +0 -145
- package/src/media/ActiveMediaPlayer.js +0 -297
- package/src/media/AudioBuffer.js +0 -219
- package/src/media/EventSounds.js +0 -169
- package/src/media/EventSoundsElement.js +0 -155
- package/src/media/MediaContent.js +0 -328
- package/src/media/MidiAudioPlayer.js +0 -254
- package/src/media/icons/audio.svg +0 -3
- package/src/media/icons/generic.svg +0 -3
- package/src/media/icons/mic.svg +0 -3
- package/src/media/icons/movie.svg +0 -3
- package/src/media/icons/music.svg +0 -3
- package/src/media/icons/url.svg +0 -3
- package/src/media/sounds/actionError.mp3 +0 -0
- package/src/media/sounds/actionOk.mp3 +0 -0
- package/src/media/sounds/click.mp3 +0 -0
- package/src/media/sounds/finishedError.mp3 +0 -0
- package/src/media/sounds/finishedOk.mp3 +0 -0
- package/src/media/sounds/start.mp3 +0 -0
- package/src/project/JClicProject.js +0 -282
- package/src/project/ProjectSettings.js +0 -273
- package/src/report/ActionReg.js +0 -123
- package/src/report/ActivityReg.js +0 -271
- package/src/report/EncryptMin.js +0 -210
- package/src/report/Reporter.js +0 -727
- package/src/report/SCORM.js +0 -272
- package/src/report/SequenceReg.js +0 -275
- package/src/report/SessionReg.js +0 -340
- package/src/report/SessionStorageReporter.js +0 -131
- package/src/report/TCPReporter.js +0 -628
- package/src/shapers/ClassicJigSaw.js +0 -138
- package/src/shapers/Holes.js +0 -77
- package/src/shapers/JigSaw.js +0 -161
- package/src/shapers/Rectangular.js +0 -78
- package/src/shapers/Shaper.js +0 -386
- package/src/shapers/TriangularJigSaw.js +0 -121
- package/src/skins/BlueSkin.js +0 -80
- package/src/skins/Counter.js +0 -152
- package/src/skins/CustomSkin.js +0 -412
- package/src/skins/DefaultSkin.js +0 -376
- package/src/skins/EmptySkin.js +0 -82
- package/src/skins/GreenSkin.js +0 -94
- package/src/skins/MiniSkin.js +0 -130
- package/src/skins/OrangeSkin.js +0 -78
- package/src/skins/SimpleSkin.js +0 -92
- package/src/skins/Skin.js +0 -1021
- package/src/skins/assets/actionsIcon.svg +0 -3
- package/src/skins/assets/appLogo.svg +0 -8
- package/src/skins/assets/basic.css +0 -41
- package/src/skins/assets/closeDialogIcon.svg +0 -3
- package/src/skins/assets/closeIcon.svg +0 -3
- package/src/skins/assets/copyIcon.svg +0 -3
- package/src/skins/assets/fullScreenExitIcon.svg +0 -3
- package/src/skins/assets/fullScreenIcon.svg +0 -3
- package/src/skins/assets/infoIcon.svg +0 -3
- package/src/skins/assets/main.css +0 -43
- package/src/skins/assets/mainHalf.css +0 -23
- package/src/skins/assets/mainTwoThirds.css +0 -23
- package/src/skins/assets/mini.css +0 -15
- package/src/skins/assets/nextIcon.svg +0 -3
- package/src/skins/assets/okDialogIcon.svg +0 -3
- package/src/skins/assets/prevIcon.svg +0 -3
- package/src/skins/assets/reports.css +0 -156
- package/src/skins/assets/reportsIcon.svg +0 -3
- package/src/skins/assets/scoreIcon.svg +0 -3
- package/src/skins/assets/simple.css +0 -16
- package/src/skins/assets/simpleHalf.css +0 -11
- package/src/skins/assets/simpleTwoThirds.css +0 -11
- package/src/skins/assets/timeIcon.svg +0 -4
- package/src/skins/assets/waitAnim.css +0 -54
- package/src/skins/assets/waitImgBig.svg +0 -3
- package/src/skins/assets/waitImgSmall.svg +0 -3
- package/webpack.config.mjs +0 -169
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File : activities/text/FillInBlanks.js
|
|
3
|
-
* Created : 20/06/2015
|
|
4
|
-
* By : Francesc Busquets <francesc@gmail.com>
|
|
5
|
-
*
|
|
6
|
-
* JClic.js
|
|
7
|
-
* An HTML5 player of JClic activities
|
|
8
|
-
* https://projectestac.github.io/jclic.js
|
|
9
|
-
*
|
|
10
|
-
* @source https://github.com/projectestac/jclic.js
|
|
11
|
-
*
|
|
12
|
-
* @license EUPL-1.2
|
|
13
|
-
* @licstart
|
|
14
|
-
* (c) 2000-2020 Catalan Educational Telematic Network (XTEC)
|
|
15
|
-
*
|
|
16
|
-
* Licensed under the EUPL, Version 1.1 or -as soon they will be approved by
|
|
17
|
-
* the European Commission- subsequent versions of the EUPL (the "Licence");
|
|
18
|
-
* You may not use this work except in compliance with the Licence.
|
|
19
|
-
*
|
|
20
|
-
* You may obtain a copy of the Licence at:
|
|
21
|
-
* https://joinup.ec.europa.eu/software/page/eupl
|
|
22
|
-
*
|
|
23
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
24
|
-
* distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
|
|
25
|
-
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
26
|
-
* Licence for the specific language governing permissions and limitations
|
|
27
|
-
* under the Licence.
|
|
28
|
-
* @licend
|
|
29
|
-
* @module
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
import Activity from '../../Activity.js';
|
|
33
|
-
import $ from 'jquery';
|
|
34
|
-
import { fillString, setSelectionRange, getCaretCharacterOffsetWithin } from '../../Utils.js';
|
|
35
|
-
import { TextActivityBase, TextActivityBasePanel } from './TextActivityBase.js';
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* In this type of activity the text document has some blanks that must be filled-in. The blanks
|
|
39
|
-
* can be drop-down boxes or text fields (empty or pre-filled with an initial text). Blanks can
|
|
40
|
-
* also have associated clues, shown as "pop-ups".
|
|
41
|
-
* @extends module:activities/text/TextActivityBase.TextActivityBase
|
|
42
|
-
*/
|
|
43
|
-
export class FillInBlanks extends TextActivityBase {
|
|
44
|
-
/**
|
|
45
|
-
* FillInBlanks constructor
|
|
46
|
-
* @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs
|
|
47
|
-
*/
|
|
48
|
-
constructor(project) {
|
|
49
|
-
super(project);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* This kind of activity usually makes use of the keyboard
|
|
54
|
-
* @override
|
|
55
|
-
* @returns {boolean}
|
|
56
|
-
*/
|
|
57
|
-
needsKeyboard() {
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
Object.assign(FillInBlanks.prototype, {
|
|
63
|
-
/**
|
|
64
|
-
* Whether to jump or not to the next target when the current one is solved.
|
|
65
|
-
* @name module:activities/text/FillInBlanks.FillInBlanks#autoJump
|
|
66
|
-
* @type {boolean} */
|
|
67
|
-
autoJump: false,
|
|
68
|
-
/**
|
|
69
|
-
* Whether to block or not the jump to other targets until the current one
|
|
70
|
-
* is resolved.
|
|
71
|
-
* @name module:activities/text/FillInBlanks.FillInBlanks#forceOkToAdvance
|
|
72
|
-
* @type {boolean} */
|
|
73
|
-
forceOkToAdvance: false,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* The {@link module:activities/text/TextActivityBase.TextActivityBasePanel} where {@link module:activities/text/FillInBlanks.FillInBlanks FillInBlanks} activities are played.
|
|
78
|
-
* @extends module:activities/text/TextActivityBase.TextActivityBasePanel
|
|
79
|
-
*/
|
|
80
|
-
export class FillInBlanksPanel extends TextActivityBasePanel {
|
|
81
|
-
/**
|
|
82
|
-
* FillInBlanksPanel constructor
|
|
83
|
-
* @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs
|
|
84
|
-
* @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the
|
|
85
|
-
* [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.
|
|
86
|
-
* @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy
|
|
87
|
-
*/
|
|
88
|
-
constructor(act, ps, $div) {
|
|
89
|
-
super(act, ps, $div);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Creates a target DOM element for the provided target. This DOM element can be an editable
|
|
94
|
-
* `span` or a `select` with specific `option` elements (when the target is a drop-down list)
|
|
95
|
-
* @override
|
|
96
|
-
* @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created
|
|
97
|
-
* @param {external:jQuery} $span - - An initial DOM object (usually a `span`) that can be used
|
|
98
|
-
* to store the target, or replaced by another type of object.
|
|
99
|
-
* @returns {external:jQuery} - The jQuery DOM element loaded with the target data.
|
|
100
|
-
*/
|
|
101
|
-
$createTargetElement(target, $span) {
|
|
102
|
-
|
|
103
|
-
$span.addClass('JClicTextTarget');
|
|
104
|
-
|
|
105
|
-
const idLabel = `target${`000${this.targets.length - 1}`.slice(-3)}`;
|
|
106
|
-
if (target.isList && target.options && target.options.length > 0) {
|
|
107
|
-
// Use a `select` element
|
|
108
|
-
$span = $('<select/>', { id: idLabel, name: idLabel });
|
|
109
|
-
if (target.options[0].trim() !== '')
|
|
110
|
-
$('<option selected/>', { value: '', text: '' }).appendTo($span);
|
|
111
|
-
target.options.forEach(op => $('<option/>', { value: op, text: op }).appendTo($span));
|
|
112
|
-
target.$comboList = $span.on('focus change', event => {
|
|
113
|
-
event.textTarget = target;
|
|
114
|
-
this.processEvent(event);
|
|
115
|
-
});
|
|
116
|
-
} else {
|
|
117
|
-
// Use a `span` element with the `contentEditable` attribute set `on`
|
|
118
|
-
target.currentText = target.iniText ?
|
|
119
|
-
target.iniText
|
|
120
|
-
: fillString(target.iniChar, target.numIniChars);
|
|
121
|
-
|
|
122
|
-
target.$span = $span.text(target.currentText).attr({
|
|
123
|
-
contenteditable: 'true',
|
|
124
|
-
id: idLabel,
|
|
125
|
-
autocomplete: 'off',
|
|
126
|
-
spellcheck: 'false'
|
|
127
|
-
}).on('focus input blur', event => {
|
|
128
|
-
event.textTarget = target;
|
|
129
|
-
this.processEvent(event);
|
|
130
|
-
}).on('keydown keyup', event => {
|
|
131
|
-
// Catch `enter` key in Firefox
|
|
132
|
-
if (event.keyCode === 13) {
|
|
133
|
-
event.preventDefault();
|
|
134
|
-
if (event.type === 'keydown') {
|
|
135
|
-
// Simulate a `blur` event
|
|
136
|
-
event.textTarget = target;
|
|
137
|
-
event.type = 'blur';
|
|
138
|
-
this.processEvent(event);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
return $span;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Evaluates all the targets in this panel. This method is usually called from the `Check` button.
|
|
148
|
-
* @override
|
|
149
|
-
* @returns {boolean} - `true` when all targets are OK, `false` otherwise.
|
|
150
|
-
*/
|
|
151
|
-
evaluatePanel() {
|
|
152
|
-
let targetsOk = 0;
|
|
153
|
-
const numTargets = this.targets.length;
|
|
154
|
-
this.targets.forEach(target => {
|
|
155
|
-
const
|
|
156
|
-
result = this.act.ev.evalText(target.readCurrentText(), target.answers),
|
|
157
|
-
ok = this.act.ev.isOk(result);
|
|
158
|
-
target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';
|
|
159
|
-
if (ok)
|
|
160
|
-
targetsOk++;
|
|
161
|
-
this.markTarget(target, result);
|
|
162
|
-
this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);
|
|
163
|
-
});
|
|
164
|
-
if (targetsOk === numTargets) {
|
|
165
|
-
this.finishActivity(true);
|
|
166
|
-
return true;
|
|
167
|
-
} else
|
|
168
|
-
this.playEvent('finishedError');
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Checks if the specified TextTarget has a valid answer in its `currentText` field
|
|
174
|
-
* @param {module:activities/text/TextActivityDocument.TextTarget} target - The target to check
|
|
175
|
-
* @param {boolean} onlyCheck - When `true`, the cursor will no be re-positioned
|
|
176
|
-
* @param {number} [jumpDirection] - `1` to go forward, `-1` to go back.
|
|
177
|
-
* @returns {boolean} - `true` when the target contains a valid answer
|
|
178
|
-
*/
|
|
179
|
-
checkTarget(target, onlyCheck, jumpDirection) {
|
|
180
|
-
const
|
|
181
|
-
result = this.act.ev.evalText(target.currentText, target.answers),
|
|
182
|
-
ok = this.act.ev.isOk(result);
|
|
183
|
-
|
|
184
|
-
target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';
|
|
185
|
-
if (onlyCheck)
|
|
186
|
-
return ok;
|
|
187
|
-
|
|
188
|
-
this.markTarget(target, result);
|
|
189
|
-
const targetsOk = this.countSolvedTargets(false, false);
|
|
190
|
-
if (target.currentText.length > 0)
|
|
191
|
-
this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);
|
|
192
|
-
if (ok && targetsOk === this.targets.length) {
|
|
193
|
-
this.finishActivity(true);
|
|
194
|
-
return ok;
|
|
195
|
-
} else if (target.currentText.length > 0)
|
|
196
|
-
this.playEvent(ok ? 'actionOk' : 'actionError');
|
|
197
|
-
|
|
198
|
-
if (jumpDirection && jumpDirection !== 0) {
|
|
199
|
-
let p = target.num + jumpDirection;
|
|
200
|
-
if (p >= this.targets.length)
|
|
201
|
-
p = 0;
|
|
202
|
-
else if (p < 0)
|
|
203
|
-
p = this.targets.length - 1;
|
|
204
|
-
|
|
205
|
-
const destTarget = this.targets[p];
|
|
206
|
-
if (destTarget.$span) {
|
|
207
|
-
destTarget.$span.trigger('focus');
|
|
208
|
-
setSelectionRange(destTarget.$span.get(-1), 0, 0);
|
|
209
|
-
} else if (destTarget.$comboList)
|
|
210
|
-
destTarget.$comboList.trigger('focus');
|
|
211
|
-
}
|
|
212
|
-
return ok;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Counts the number of targets with `SOLVED` status
|
|
217
|
-
* @param {boolean} checkNow - When `true`, all targets will be evaluated. Otherwise, only the
|
|
218
|
-
* current value of `targetStatus` will be checked.
|
|
219
|
-
* @param {boolean} [mark] - When `true`, errors in the target answer will be marked.
|
|
220
|
-
* @returns {number} - The number of targets currently solved.
|
|
221
|
-
*/
|
|
222
|
-
countSolvedTargets(checkNow, mark) {
|
|
223
|
-
return this.targets.reduce((n, target) => {
|
|
224
|
-
if (checkNow) {
|
|
225
|
-
target.readCurrentText();
|
|
226
|
-
this.checkTarget(target, !mark);
|
|
227
|
-
}
|
|
228
|
-
return target.targetStatus === 'SOLVED' ? ++n : n;
|
|
229
|
-
}, 0);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Visually marks the target as 'solved OK' or 'with errors'.
|
|
234
|
-
* @param {module:activities/text/TextActivityDocument.TextTarget} target - The text target to be marked.
|
|
235
|
-
* @param {number[]} attributes - - Array of flags indicating the status (OK or error) for each
|
|
236
|
-
* character in `target.currentText`.
|
|
237
|
-
*/
|
|
238
|
-
markTarget(target, attributes) {
|
|
239
|
-
if (target.$comboList || this.act.ev.isOk(attributes))
|
|
240
|
-
target.checkColors();
|
|
241
|
-
else if (target.$span) {
|
|
242
|
-
// Identify text fragments
|
|
243
|
-
const
|
|
244
|
-
txt = target.currentText,
|
|
245
|
-
fragments = [];
|
|
246
|
-
let
|
|
247
|
-
currentStatus = -1,
|
|
248
|
-
currentFragment = -1,
|
|
249
|
-
i = 0;
|
|
250
|
-
for (; i < attributes.length && i < txt.length; i++) {
|
|
251
|
-
if (attributes[i] !== currentStatus) {
|
|
252
|
-
fragments[++currentFragment] = '';
|
|
253
|
-
currentStatus = attributes[i];
|
|
254
|
-
}
|
|
255
|
-
fragments[currentFragment] += txt.charAt(i);
|
|
256
|
-
}
|
|
257
|
-
if (i < txt.length)
|
|
258
|
-
fragments[currentFragment] += txt.substring(i);
|
|
259
|
-
// Empty and re-fill $span
|
|
260
|
-
target.$span.empty();
|
|
261
|
-
currentStatus = attributes[0];
|
|
262
|
-
fragments.forEach(fragment => {
|
|
263
|
-
$('<span/>')
|
|
264
|
-
.text(fragment)
|
|
265
|
-
.css(target.doc.style[currentStatus === 0 ? 'target' : 'targetError'].css)
|
|
266
|
-
.appendTo(target.$span);
|
|
267
|
-
currentStatus ^= 1;
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
// Target has been marked, so clear the 'modified' flag
|
|
271
|
-
target.flagModified = false;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Called by {@link module:JClicPlayer.JClicPlayer JClicPlayer} when this activity panel is fully visible, just after the
|
|
276
|
-
* initialization process.
|
|
277
|
-
* @override
|
|
278
|
-
*/
|
|
279
|
-
activityReady() {
|
|
280
|
-
super.activityReady();
|
|
281
|
-
|
|
282
|
-
// Prevent strange behavior with GoogleChrome when `white-space` CSS attribute is set to
|
|
283
|
-
// `pre-wrap` (needed for tabulated texts)
|
|
284
|
-
$('.JClicTextTarget').css('white-space', 'normal');
|
|
285
|
-
if (this.targets.length > 0 && this.targets[0].$span)
|
|
286
|
-
this.targets[0].$span.trigger('focus');
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Ordinary ending of the activity, usually called form `processEvent`
|
|
291
|
-
* @override
|
|
292
|
-
* @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise
|
|
293
|
-
*/
|
|
294
|
-
finishActivity(result) {
|
|
295
|
-
this.targets.forEach(target => {
|
|
296
|
-
if (target.$span)
|
|
297
|
-
target.$span.removeAttr('contenteditable').trigger('blur');
|
|
298
|
-
else if (target.$comboList)
|
|
299
|
-
target.$comboList.prop('disabled', true).trigger('blur');
|
|
300
|
-
});
|
|
301
|
-
return super.finishActivity(result);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Main handler used to process mouse, touch, keyboard and edit events.
|
|
306
|
-
* @override
|
|
307
|
-
* @param {external:Event} event - The HTML event to be processed
|
|
308
|
-
* @returns {boolean} - When this event handler returns `false`, jQuery will stop its
|
|
309
|
-
* propagation through the DOM tree. See: {@link http://api.jquery.com/on}
|
|
310
|
-
*/
|
|
311
|
-
processEvent(event) {
|
|
312
|
-
if (!super.processEvent(event))
|
|
313
|
-
return false;
|
|
314
|
-
|
|
315
|
-
const target = event.textTarget;
|
|
316
|
-
let $span = null, pos = 0;
|
|
317
|
-
switch (event.type) {
|
|
318
|
-
case 'focus':
|
|
319
|
-
if (target) {
|
|
320
|
-
if (target.$span && target.$span.children().length > 0) {
|
|
321
|
-
// Clear inner spans used to mark errors
|
|
322
|
-
$span = target.$span;
|
|
323
|
-
pos = Math.min(
|
|
324
|
-
target.currentText.length,
|
|
325
|
-
getCaretCharacterOffsetWithin($span.get(-1)));
|
|
326
|
-
$span.empty();
|
|
327
|
-
$span.text(target.currentText);
|
|
328
|
-
setSelectionRange($span.get(-1), pos, pos);
|
|
329
|
-
target.flagModified = true;
|
|
330
|
-
} else if (target.$comboList)
|
|
331
|
-
target.$comboList.css(target.doc.style['target'].css);
|
|
332
|
-
|
|
333
|
-
if (target.$popup && (target.infoMode === 'always' || target.infoMode === 'onError' && target.targetStatus === 'WITH_ERROR'))
|
|
334
|
-
this.showPopup(target.$popup, target.popupMaxTime, target.popupDelay);
|
|
335
|
-
else
|
|
336
|
-
this.showPopup(null);
|
|
337
|
-
}
|
|
338
|
-
break;
|
|
339
|
-
|
|
340
|
-
case 'blur':
|
|
341
|
-
if (target.flagModified && !this.$checkButton)
|
|
342
|
-
this.checkTarget(target, false, 1);
|
|
343
|
-
break;
|
|
344
|
-
|
|
345
|
-
case 'input':
|
|
346
|
-
if (target && target.$span) {
|
|
347
|
-
$span = target.$span;
|
|
348
|
-
let txt = $span.html();
|
|
349
|
-
// Check for `enter` key
|
|
350
|
-
if (/(<br>|\n|\r)/.test(txt)) {
|
|
351
|
-
txt = txt.replace(/(<br>|\n|\r)/g, '');
|
|
352
|
-
$span.html(txt);
|
|
353
|
-
target.currentText = $span.text();
|
|
354
|
-
return this.$checkButton ? false : this.checkTarget(target, false, 1);
|
|
355
|
-
}
|
|
356
|
-
// Check if text has changed
|
|
357
|
-
// From here, use 'text' instead of 'html' to avoid HTML entities
|
|
358
|
-
txt = $span.text();
|
|
359
|
-
if (txt !== target.currentText) {
|
|
360
|
-
// Span text has changed!
|
|
361
|
-
target.flagModified = true;
|
|
362
|
-
const added = txt.length - target.currentText.length;
|
|
363
|
-
if (added > 0) {
|
|
364
|
-
if (txt.indexOf(target.iniChar) >= 0) {
|
|
365
|
-
// Remove filling chars
|
|
366
|
-
pos = getCaretCharacterOffsetWithin($span.get(-1));
|
|
367
|
-
for (let i = 0; i < added; i++) {
|
|
368
|
-
const p = txt.indexOf(target.iniChar);
|
|
369
|
-
if (p < 0)
|
|
370
|
-
break;
|
|
371
|
-
txt = txt.substring(0, p) + txt.substring(p + 1);
|
|
372
|
-
if (p < pos)
|
|
373
|
-
pos--;
|
|
374
|
-
}
|
|
375
|
-
$span.text(txt);
|
|
376
|
-
setSelectionRange($span.get(-1), pos, pos);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Check if current text exceeds max length
|
|
380
|
-
if (txt.length > target.maxLenResp) {
|
|
381
|
-
pos = getCaretCharacterOffsetWithin($span.get(-1));
|
|
382
|
-
txt = txt.substring(0, target.maxLenResp);
|
|
383
|
-
pos = Math.min(pos, txt.length);
|
|
384
|
-
$span.text(txt);
|
|
385
|
-
setSelectionRange($span.get(-1), pos, pos);
|
|
386
|
-
}
|
|
387
|
-
} else if (txt === '') {
|
|
388
|
-
txt = target.iniChar;
|
|
389
|
-
$span.text(txt);
|
|
390
|
-
setSelectionRange($span.get(-1), 0, 0);
|
|
391
|
-
}
|
|
392
|
-
target.currentText = txt;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
break;
|
|
396
|
-
|
|
397
|
-
case 'change':
|
|
398
|
-
if (target && target.$comboList) {
|
|
399
|
-
target.currentText = target.$comboList.val();
|
|
400
|
-
target.flagModified = true;
|
|
401
|
-
return this.$checkButton ? false : this.checkTarget(target, false, 1);
|
|
402
|
-
}
|
|
403
|
-
break;
|
|
404
|
-
|
|
405
|
-
default:
|
|
406
|
-
break;
|
|
407
|
-
}
|
|
408
|
-
return true;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
Object.assign(FillInBlanksPanel.prototype, {
|
|
413
|
-
/**
|
|
414
|
-
* Flag indicating if the activity is open or locked
|
|
415
|
-
* @name module:activities/text/FillInBlanks.FillInBlanksPanel#locked
|
|
416
|
-
* @type {boolean} */
|
|
417
|
-
locked: true,
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Panel class associated to this type of activity: {@link module:activities/text/FillInBlanks.FillInBlanksPanel FillInBlanksPanel}
|
|
422
|
-
* @type {class} */
|
|
423
|
-
FillInBlanks.Panel = FillInBlanksPanel;
|
|
424
|
-
|
|
425
|
-
// Register activity class
|
|
426
|
-
export default Activity.registerClass('@text.FillInBlanks', FillInBlanks);
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File : activities/text/Identify.js
|
|
3
|
-
* Created : 20/06/2015
|
|
4
|
-
* By : Francesc Busquets <francesc@gmail.com>
|
|
5
|
-
*
|
|
6
|
-
* JClic.js
|
|
7
|
-
* An HTML5 player of JClic activities
|
|
8
|
-
* https://projectestac.github.io/jclic.js
|
|
9
|
-
*
|
|
10
|
-
* @source https://github.com/projectestac/jclic.js
|
|
11
|
-
*
|
|
12
|
-
* @license EUPL-1.2
|
|
13
|
-
* @licstart
|
|
14
|
-
* (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)
|
|
15
|
-
*
|
|
16
|
-
* Licensed under the EUPL, Version 1.1 or -as soon they will be approved by
|
|
17
|
-
* the European Commission- subsequent versions of the EUPL (the "Licence");
|
|
18
|
-
* You may not use this work except in compliance with the Licence.
|
|
19
|
-
*
|
|
20
|
-
* You may obtain a copy of the Licence at:
|
|
21
|
-
* https://joinup.ec.europa.eu/software/page/eupl
|
|
22
|
-
*
|
|
23
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
24
|
-
* distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
|
|
25
|
-
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
26
|
-
* Licence for the specific language governing permissions and limitations
|
|
27
|
-
* under the Licence.
|
|
28
|
-
* @licend
|
|
29
|
-
* @module
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
import Activity from '../../Activity.js';
|
|
33
|
-
import { TextActivityBase, TextActivityBasePanel } from './TextActivityBase.js';
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* This type of text activity suggests users to click on specific words or single letters of a
|
|
37
|
-
* given text, without any help on where these elements are placed.
|
|
38
|
-
* @extends module:activities/text/TextActivityBase.TextActivityBase
|
|
39
|
-
*/
|
|
40
|
-
export class IdentifyText extends TextActivityBase {
|
|
41
|
-
/**
|
|
42
|
-
* IdentifyText constructor
|
|
43
|
-
* @param {module:project/JClicProject.JClicProject} project - The project to which this activity belongs
|
|
44
|
-
*/
|
|
45
|
-
constructor(project) {
|
|
46
|
-
super(project);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The {@link module:activities/text/TextActivityBase.TextActivityBasePanel TextActivityBasePanel} where {@link module:activities/text/IdentifyText.IdentifyText IdentifyText} activities are played.
|
|
52
|
-
* @extends module:activities/text/TextActivityBase.TextActivityBasePanel
|
|
53
|
-
*/
|
|
54
|
-
class IdentifyTextPanel extends TextActivityBasePanel {
|
|
55
|
-
/**
|
|
56
|
-
* IdentifyTextPanel constructor
|
|
57
|
-
* @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs
|
|
58
|
-
* @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the
|
|
59
|
-
* [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.
|
|
60
|
-
* @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy
|
|
61
|
-
*/
|
|
62
|
-
constructor(act, ps, $div) {
|
|
63
|
-
super(act, ps, $div);
|
|
64
|
-
this.spanText = true;
|
|
65
|
-
this.spanChars = act.type === 'identifyChars';
|
|
66
|
-
this.spansChecked = new Set();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Creates a target DOM element for the provided target.
|
|
71
|
-
* @override
|
|
72
|
-
* @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created
|
|
73
|
-
* @param {external:jQuery} $span - - An initial DOM object (usually a `span`) that can be used
|
|
74
|
-
* to store the target, or replaced by another type of object.
|
|
75
|
-
* @returns {external:jQuery} - The jQuery DOM element loaded with the target data.
|
|
76
|
-
*/
|
|
77
|
-
$createTargetElement(target, $span) {
|
|
78
|
-
super.$createTargetElement(target, $span);
|
|
79
|
-
const idLabel = `target${`000${this.targets.length - 1}`.slice(-3)}`;
|
|
80
|
-
$span.on('click', event => {
|
|
81
|
-
event.textTarget = target;
|
|
82
|
-
event.idLabel = idLabel;
|
|
83
|
-
this.processEvent(event);
|
|
84
|
-
});
|
|
85
|
-
return $span;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
$createSpanElement($span) {
|
|
89
|
-
$span.on('click', event => {
|
|
90
|
-
event.$spanElement = $span;
|
|
91
|
-
this.processEvent(event);
|
|
92
|
-
});
|
|
93
|
-
return $span;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Basic initialization procedure
|
|
98
|
-
* @override
|
|
99
|
-
*/
|
|
100
|
-
initActivity() {
|
|
101
|
-
super.initActivity(this);
|
|
102
|
-
this.$div.find('.JClicTextDocument > p').css('cursor', 'pointer');
|
|
103
|
-
this.$div.find('.JClicTextDocument > span').css('cursor', 'pointer');
|
|
104
|
-
// Clean possible previous errors
|
|
105
|
-
this.spansChecked.forEach($spanElement => $spanElement.css($spanElement.initialCSS || this.act.document.style['default'].css));
|
|
106
|
-
this.spansChecked.clear();
|
|
107
|
-
this.playing = true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Counts the number of targets that are solved
|
|
112
|
-
* @returns {number}
|
|
113
|
-
*/
|
|
114
|
-
countSolvedTargets() {
|
|
115
|
-
return this.targets.filter(({ targetStatus }) => targetStatus === 'SOLVED').length;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Evaluates all the targets in this panel. This method is usually called from the `Check` button.
|
|
120
|
-
* @override
|
|
121
|
-
* @returns {boolean} - `true` when all targets are OK, `false` otherwise.
|
|
122
|
-
*/
|
|
123
|
-
evaluatePanel() {
|
|
124
|
-
let targetsOk = 0;
|
|
125
|
-
this.targets.forEach(target => {
|
|
126
|
-
const ok = target.targetStatus === 'SOLVED';
|
|
127
|
-
if (ok)
|
|
128
|
-
targetsOk++;
|
|
129
|
-
target.checkColors();
|
|
130
|
-
this.ps.reportNewAction(this.act, 'SELECT', target.text, target.pos, ok, targetsOk);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (targetsOk === this.targets.length && this.spansChecked.size === 0) {
|
|
135
|
-
this.finishActivity(true);
|
|
136
|
-
return true;
|
|
137
|
-
} else {
|
|
138
|
-
// Mark selected spans as error
|
|
139
|
-
this.spansChecked.forEach($spanElement => $spanElement.css(this.act.document.style['targetError'].css));
|
|
140
|
-
this.playEvent('finishedError');
|
|
141
|
-
}
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Ordinary ending of the activity, usually called form `processEvent`
|
|
147
|
-
* @override
|
|
148
|
-
* @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise
|
|
149
|
-
*/
|
|
150
|
-
finishActivity(result) {
|
|
151
|
-
this.$div.find('.JClicTextDocument > p').css('cursor', 'pointer');
|
|
152
|
-
return super.finishActivity(result);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Main handler used to process mouse, touch, keyboard and edit events.
|
|
157
|
-
* @override
|
|
158
|
-
* @param {external:Event} event - The HTML event to be processed
|
|
159
|
-
* @returns {boolean} - When this event handler returns `false`, jQuery will stop its
|
|
160
|
-
* propagation through the DOM tree. See: {@link http://api.jquery.com/on}
|
|
161
|
-
*/
|
|
162
|
-
processEvent(event) {
|
|
163
|
-
if (!super.processEvent(event) ||
|
|
164
|
-
event.timeStamp === this.lastTimeStamp)
|
|
165
|
-
return false;
|
|
166
|
-
|
|
167
|
-
if (event.timeStamp)
|
|
168
|
-
this.lastTimeStamp = event.timeStamp;
|
|
169
|
-
|
|
170
|
-
const target = event.textTarget;
|
|
171
|
-
const $spanElement = event.$spanElement;
|
|
172
|
-
|
|
173
|
-
switch (event.type) {
|
|
174
|
-
case 'click':
|
|
175
|
-
let text, pos, ok = false;
|
|
176
|
-
if (target) {
|
|
177
|
-
if (target.targetStatus === 'SOLVED')
|
|
178
|
-
target.targetStatus = 'HIDDEN';
|
|
179
|
-
else {
|
|
180
|
-
target.targetStatus = 'SOLVED';
|
|
181
|
-
ok = true;
|
|
182
|
-
}
|
|
183
|
-
text = target.text;
|
|
184
|
-
pos = target.pos;
|
|
185
|
-
// TODO: Just on/off target colors, don't mark it as error!
|
|
186
|
-
target.checkColors();
|
|
187
|
-
} else {
|
|
188
|
-
if ($spanElement) {
|
|
189
|
-
$spanElement.checked = !$spanElement.checked;
|
|
190
|
-
if ($spanElement.checked) {
|
|
191
|
-
this.spansChecked.add($spanElement);
|
|
192
|
-
$spanElement.css(this.act.document.style.target.css);
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
this.spansChecked.delete($spanElement);
|
|
196
|
-
$spanElement.css($spanElement.initialCSS || this.act.document.style.default.css);
|
|
197
|
-
}
|
|
198
|
-
text = $spanElement.text();
|
|
199
|
-
}
|
|
200
|
-
else
|
|
201
|
-
text = 'unknown';
|
|
202
|
-
pos = 0;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (!this.$checkButton) {
|
|
206
|
-
// Check and notify action
|
|
207
|
-
const cellsAtPlace = this.countSolvedTargets();
|
|
208
|
-
this.ps.reportNewAction(this.act, 'SELECT', text, pos, ok, cellsAtPlace);
|
|
209
|
-
|
|
210
|
-
// End activity or play event sound
|
|
211
|
-
if (ok && this.spansChecked.size === 0 && cellsAtPlace === this.targets.length)
|
|
212
|
-
this.finishActivity(true);
|
|
213
|
-
else
|
|
214
|
-
this.playEvent(ok ? 'actionOk' : 'actionError');
|
|
215
|
-
}
|
|
216
|
-
event.preventDefault();
|
|
217
|
-
break;
|
|
218
|
-
|
|
219
|
-
default:
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
return true;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
Object.assign(IdentifyTextPanel.prototype, {
|
|
227
|
-
/**
|
|
228
|
-
* Flag indicating if targets must be visually marked when the activity begins. In this type of
|
|
229
|
-
* activity should be always `false` to avoid revealing the words o letters that must be found.
|
|
230
|
-
* @name module:activities/text/IdentifyText.IdentifyTextPanel#targetsMarked
|
|
231
|
-
* @type {boolean} */
|
|
232
|
-
targetsMarked: false,
|
|
233
|
-
/**
|
|
234
|
-
* Used to avoid duplicate event processing
|
|
235
|
-
* @name module:activities/text/IdentifyText.IdentifyTextPanel#lastTimeStamp
|
|
236
|
-
* @type {number}
|
|
237
|
-
*/
|
|
238
|
-
lastTimeStamp: 0,
|
|
239
|
-
/**
|
|
240
|
-
* Set of non-target spans currently selected by the player.
|
|
241
|
-
* This attribute should be empty to solve the activity.
|
|
242
|
-
* @name module:activities/text/IdentifyText.IdentifyTextPanel#spansChecked
|
|
243
|
-
* @type {set} */
|
|
244
|
-
spansChecked: new Set(),
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Panel class associated to this type of activity: {@link module:activities/text/IdentifyText.IdentifyTextPanel IdentifyTextPanel}
|
|
249
|
-
* @type {class} */
|
|
250
|
-
IdentifyText.Panel = IdentifyTextPanel;
|
|
251
|
-
|
|
252
|
-
// Register activity class
|
|
253
|
-
export default Activity.registerClass('@text.Identify', IdentifyText);
|