jclic 2.1.21 → 2.1.23

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.
Files changed (175) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/jclic-node.js +9 -8
  3. package/dist/jclic-node.js.map +1 -1
  4. package/dist/jclic.min.js +2 -2
  5. package/dist/jclic.min.js.map +1 -1
  6. package/package.json +4 -4
  7. package/src/GlobalData.js +1 -1
  8. package/src/JClicPlayer.js +2 -2
  9. package/src/bags/MediaBag.js +6 -5
  10. package/dist/1078.jclic-node.js +0 -282
  11. package/dist/1078.jclic-node.js.map +0 -1
  12. package/dist/1196.jclic-node.js +0 -808
  13. package/dist/1196.jclic-node.js.map +0 -1
  14. package/dist/1253.jclic-node.js +0 -1432
  15. package/dist/1253.jclic-node.js.map +0 -1
  16. package/dist/13.jclic-node.js +0 -103
  17. package/dist/13.jclic-node.js.map +0 -1
  18. package/dist/1567.jclic-node.js +0 -2313
  19. package/dist/1567.jclic-node.js.map +0 -1
  20. package/dist/1588.jclic-node.js +0 -602
  21. package/dist/1588.jclic-node.js.map +0 -1
  22. package/dist/1725.jclic-node.js +0 -836
  23. package/dist/1725.jclic-node.js.map +0 -1
  24. package/dist/1731.jclic-node.js +0 -438
  25. package/dist/1731.jclic-node.js.map +0 -1
  26. package/dist/1842.jclic-node.js +0 -651
  27. package/dist/1842.jclic-node.js.map +0 -1
  28. package/dist/2160.jclic-node.js +0 -1016
  29. package/dist/2160.jclic-node.js.map +0 -1
  30. package/dist/222.jclic-node.js +0 -129
  31. package/dist/222.jclic-node.js.map +0 -1
  32. package/dist/2316.jclic-node.js +0 -949
  33. package/dist/2316.jclic-node.js.map +0 -1
  34. package/dist/2355.jclic-node.js +0 -371
  35. package/dist/2355.jclic-node.js.map +0 -1
  36. package/dist/2366.jclic-node.js +0 -431
  37. package/dist/2366.jclic-node.js.map +0 -1
  38. package/dist/2379.jclic-node.js +0 -202
  39. package/dist/2379.jclic-node.js.map +0 -1
  40. package/dist/2437.jclic-node.js +0 -450
  41. package/dist/2437.jclic-node.js.map +0 -1
  42. package/dist/2531.jclic-node.js +0 -869
  43. package/dist/2531.jclic-node.js.map +0 -1
  44. package/dist/2608.jclic-node.js +0 -160
  45. package/dist/2608.jclic-node.js.map +0 -1
  46. package/dist/2715.jclic-node.js +0 -554
  47. package/dist/2715.jclic-node.js.map +0 -1
  48. package/dist/277.jclic-node.js +0 -22
  49. package/dist/277.jclic-node.js.map +0 -1
  50. package/dist/2921.jclic-node.js +0 -660
  51. package/dist/2921.jclic-node.js.map +0 -1
  52. package/dist/2952.jclic-node.js +0 -101
  53. package/dist/2952.jclic-node.js.map +0 -1
  54. package/dist/3018.jclic-node.js +0 -421
  55. package/dist/3018.jclic-node.js.map +0 -1
  56. package/dist/3019.jclic-node.js +0 -682
  57. package/dist/3019.jclic-node.js.map +0 -1
  58. package/dist/3231.jclic-node.js +0 -274
  59. package/dist/3231.jclic-node.js.map +0 -1
  60. package/dist/331.jclic-node.js +0 -115
  61. package/dist/331.jclic-node.js.map +0 -1
  62. package/dist/3391.jclic-node.js +0 -276
  63. package/dist/3391.jclic-node.js.map +0 -1
  64. package/dist/3502.jclic-node.js +0 -671
  65. package/dist/3502.jclic-node.js.map +0 -1
  66. package/dist/3653.jclic-node.js +0 -982
  67. package/dist/3653.jclic-node.js.map +0 -1
  68. package/dist/371.jclic.min.js +0 -2
  69. package/dist/371.jclic.min.js.map +0 -1
  70. package/dist/3856.jclic-node.js +0 -575
  71. package/dist/3856.jclic-node.js.map +0 -1
  72. package/dist/4112.jclic-node.js +0 -659
  73. package/dist/4112.jclic-node.js.map +0 -1
  74. package/dist/4123.jclic-node.js +0 -910
  75. package/dist/4123.jclic-node.js.map +0 -1
  76. package/dist/427.jclic-node.js +0 -894
  77. package/dist/427.jclic-node.js.map +0 -1
  78. package/dist/4483.jclic-node.js +0 -327
  79. package/dist/4483.jclic-node.js.map +0 -1
  80. package/dist/4548.jclic-node.js +0 -1078
  81. package/dist/4548.jclic-node.js.map +0 -1
  82. package/dist/466.jclic-node.js +0 -99
  83. package/dist/466.jclic-node.js.map +0 -1
  84. package/dist/485.jclic-node.js +0 -783
  85. package/dist/485.jclic-node.js.map +0 -1
  86. package/dist/4921.jclic-node.js +0 -500
  87. package/dist/4921.jclic-node.js.map +0 -1
  88. package/dist/5091.jclic-node.js +0 -239
  89. package/dist/5091.jclic-node.js.map +0 -1
  90. package/dist/520.jclic-node.js +0 -550
  91. package/dist/520.jclic-node.js.map +0 -1
  92. package/dist/5312.jclic-node.js +0 -1126
  93. package/dist/5312.jclic-node.js.map +0 -1
  94. package/dist/5338.jclic-node.js +0 -212
  95. package/dist/5338.jclic-node.js.map +0 -1
  96. package/dist/5344.jclic-node.js +0 -229
  97. package/dist/5344.jclic-node.js.map +0 -1
  98. package/dist/5550.jclic-node.js +0 -238
  99. package/dist/5550.jclic-node.js.map +0 -1
  100. package/dist/5626.jclic-node.js +0 -614
  101. package/dist/5626.jclic-node.js.map +0 -1
  102. package/dist/5977.jclic-node.js +0 -1081
  103. package/dist/5977.jclic-node.js.map +0 -1
  104. package/dist/6148.jclic-node.js +0 -345
  105. package/dist/6148.jclic-node.js.map +0 -1
  106. package/dist/6176.jclic-node.js +0 -481
  107. package/dist/6176.jclic-node.js.map +0 -1
  108. package/dist/6221.jclic-node.js +0 -1072
  109. package/dist/6221.jclic-node.js.map +0 -1
  110. package/dist/6238.jclic-node.js +0 -718
  111. package/dist/6238.jclic-node.js.map +0 -1
  112. package/dist/6454.jclic-node.js +0 -1413
  113. package/dist/6454.jclic-node.js.map +0 -1
  114. package/dist/6565.jclic-node.js +0 -294
  115. package/dist/6565.jclic-node.js.map +0 -1
  116. package/dist/6579.jclic-node.js +0 -719
  117. package/dist/6579.jclic-node.js.map +0 -1
  118. package/dist/6715.jclic-node.js +0 -148
  119. package/dist/6715.jclic-node.js.map +0 -1
  120. package/dist/6777.jclic-node.js +0 -171
  121. package/dist/6777.jclic-node.js.map +0 -1
  122. package/dist/6782.jclic-node.js +0 -1611
  123. package/dist/6782.jclic-node.js.map +0 -1
  124. package/dist/6847.jclic-node.js +0 -601
  125. package/dist/6847.jclic-node.js.map +0 -1
  126. package/dist/6856.jclic-node.js +0 -252
  127. package/dist/6856.jclic-node.js.map +0 -1
  128. package/dist/696.jclic-node.js +0 -1821
  129. package/dist/696.jclic-node.js.map +0 -1
  130. package/dist/698.jclic-node.js +0 -583
  131. package/dist/698.jclic-node.js.map +0 -1
  132. package/dist/704.jclic-node.js +0 -80
  133. package/dist/704.jclic-node.js.map +0 -1
  134. package/dist/7046.jclic-node.js +0 -735
  135. package/dist/7046.jclic-node.js.map +0 -1
  136. package/dist/7220.jclic-node.js +0 -156
  137. package/dist/7220.jclic-node.js.map +0 -1
  138. package/dist/7257.jclic-node.js +0 -931
  139. package/dist/7257.jclic-node.js.map +0 -1
  140. package/dist/743.jclic-node.js +0 -583
  141. package/dist/743.jclic-node.js.map +0 -1
  142. package/dist/757.jclic-node.js +0 -1072
  143. package/dist/757.jclic-node.js.map +0 -1
  144. package/dist/7781.jclic-node.js +0 -202
  145. package/dist/7781.jclic-node.js.map +0 -1
  146. package/dist/7912.jclic-node.js +0 -2103
  147. package/dist/7912.jclic-node.js.map +0 -1
  148. package/dist/827.jclic-node.js +0 -708
  149. package/dist/827.jclic-node.js.map +0 -1
  150. package/dist/8276.jclic-node.js +0 -409
  151. package/dist/8276.jclic-node.js.map +0 -1
  152. package/dist/8322.jclic-node.js +0 -498
  153. package/dist/8322.jclic-node.js.map +0 -1
  154. package/dist/8641.jclic-node.js +0 -360
  155. package/dist/8641.jclic-node.js.map +0 -1
  156. package/dist/8837.jclic-node.js +0 -651
  157. package/dist/8837.jclic-node.js.map +0 -1
  158. package/dist/8895.jclic-node.js +0 -151
  159. package/dist/8895.jclic-node.js.map +0 -1
  160. package/dist/9072.jclic-node.js +0 -1285
  161. package/dist/9072.jclic-node.js.map +0 -1
  162. package/dist/9078.jclic-node.js +0 -935
  163. package/dist/9078.jclic-node.js.map +0 -1
  164. package/dist/9103.jclic-node.js +0 -718
  165. package/dist/9103.jclic-node.js.map +0 -1
  166. package/dist/9359.jclic-node.js +0 -145
  167. package/dist/9359.jclic-node.js.map +0 -1
  168. package/dist/9409.jclic-node.js +0 -921
  169. package/dist/9409.jclic-node.js.map +0 -1
  170. package/dist/9513.jclic-node.js +0 -720
  171. package/dist/9513.jclic-node.js.map +0 -1
  172. package/dist/9704.jclic-node.js +0 -81
  173. package/dist/9704.jclic-node.js.map +0 -1
  174. package/dist/9950.jclic-node.js +0 -827
  175. package/dist/9950.jclic-node.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"2379.jclic-node.js","mappings":";;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEyC;;AAEzC;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oCAAoC;AACpC,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,wDAAG,gDAAgD,UAAU;AACrE;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA,WAAW,4DAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,qFAAqF;AACrG,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,kDAAkD,gDAAgD;AAC/G;AACA,aAAa,SAAS,yCAAyC,uEAAuE;AACtI,eAAe,SAAS;AACxB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,2DAA2D;AACxE,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe,2DAA2D;AAC1E;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,kDAAkD,gDAAgD;AAC7G;AACA,WAAW,SAAS,wCAAwC,uEAAuE;AACnI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oEAAoE,iDAAiD;AACrH,UAAU,QAAQ;AAClB;AACA;AACA;AACA;;AAEA;AACA;;AAEA,iEAAe,mBAAmB,EAAC","sources":["webpack://jclic/./src/automation/AutoContentProvider.js"],"sourcesContent":["/**\n * File : automation/AutoContentProvider.js\n * Created : 13/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport {log, getAttr} from '../Utils.js';\n\n/**\n * This abstract class is the base for classes that create on-time automatic content for JClic\n * activities, usually using random parameters to assure different content in each session.\n *\n * Activities with `AutoContentProvider` objects rely on them to build new content on every start.\n */\nexport class AutoContentProvider {\n /**\n * AutoContentProvider constructor\n */\n constructor() {\n }\n\n /**\n * Dynamic constructor that returns a specific type of AutoContentProvider based on the `class`\n * attribute declared on an $xml element.\n * It should be called only from {@link module:Activity.Activity#setProperties Activity.setProperties}\n * @param {external.jQuery} $xml - The XML element to parse\n * @returns {module:automation/AutoContentProvider.AutoContentProvider}\n */\n static getProvider($xml) {\n let automation = null;\n if ($xml) {\n const\n className = ($xml.attr('class') || '').replace(/^edu\\.xtec\\.jclic\\.automation\\./, '@'),\n cl = AutoContentProvider.CLASSES[className];\n if (cl) {\n automation = new cl();\n automation.setProperties($xml);\n } else\n log('error', `Unknown AutoContentProvider class: ${className}`);\n }\n return automation;\n }\n\n /**\n * Loads the object settings from a specific jQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n this.className = ($xml.attr('class') || '').replace(/^edu\\.xtec\\.jclic\\.automation\\./, '@');\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n // To be overrided!\n return getAttr(this, ['className']);\n }\n\n /**\n * Builds a new AutoContentProvider, based on the properties specified in a data object\n * @param {object} data - The data object to be parsed\n * @param {object[]} params - Optional parameters to be passed to `setAttributes`\n * @returns {module:shapers/Shaper.Shaper}\n */\n static factory(data, params = []) {\n const cl = AutoContentProvider.CLASSES[data.className];\n return (new cl()).setAttributes(data, ...params);\n }\n\n /**\n * Initializes the content provider\n */\n init() {\n // To be implemented in real content providers\n }\n\n /**\n * Builds an {@link module:automation/AutoContentProvider/ActiveBagContentKit ActiveBagContentKit} and generates the automatized content.\n * @param {number} nRows - Number of rows to be processed\n * @param {number} nCols - Number of columns to be processed\n * @param {module:boxes/ActiveBagContent.ActiveBagContent[]} content - Array with one or more containers of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent}\n * objects to be filled with new content.\n * @param {boolean} useIds - When `true`, the `id` field of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} objects is significant\n * @returns {boolean} - `true` if the process was OK. `false` otherwise.\n */\n generateContent(nRows, nCols, content, useIds) {\n return this.process(new AutoContentProvider.ActiveBagContentKit(nRows, nCols, content, useIds));\n }\n\n /**\n * Generates the automatized content\n * @param {module:automation/AutoContentProvider.ActiveBagContentKit} _kit - The objects to be filled with content\n * @returns {boolean} - `true` if the process was OK. `false` otherwise.\n */\n process(_kit) {\n // To be implemented in subclasses\n return false;\n }\n\n /**\n * Registers a new type of AutoContentProvider\n * @param {string} providerName - The name used to identify this AutoContentProvider\n * @param {function} providerClass - The activity class, usually extending AutoContentProvider\n * @returns {module:automation/AutoContentProvider.AutoContentProvider} - The provider class\n */\n static registerClass(providerName, providerClass) {\n AutoContentProvider.CLASSES[providerName] = providerClass;\n return providerClass;\n }\n}\n\nObject.assign(AutoContentProvider.prototype, {\n /**\n * This AutoContentProvider manages numeric expressions, so text literals should be\n * converted to numbers for comparisions, taking in account the\n * number format of the current locale (dot or comma as decimal separator)\n * @name module:automation/AutoContentProvider.AutoContentProvider#numericContent\n * @type {boolean} */\n numericContent: false,\n});\n\n/**\n * Utility class used to encapsulate multiple sets of box contents\n * @param {number} nRows - Number of rows to be processed\n * @param {number} nCols - Number of columns to be processed\n * @param {module:boxes/ActiveBagContent.ActiveBagContent[]} content - Array with one or more containers of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent}\n * objects to be filled with new content.\n * @param {boolean} useIds - `true` when the `id` field of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} objects is significant.\n */\nAutoContentProvider.ActiveBagContentKit = class {\n constructor(nRows, nCols, content, useIds) {\n this.nRows = nRows;\n this.nCols = nCols;\n this.content = content;\n this.useIds = useIds;\n }\n};\n\n/**\n * Contains the current list of classes derived from AutoContentProvider.\n * This object should be updated by real automation classes at declaration time.\n * Currently, only two types of \"AutoContentProvider\" are defined: {@link module:automation/arith/Arith.Arith Arith} and TagReplace.\n * @type {object} */\nAutoContentProvider.CLASSES = {\n // TODO: Implement TagReplace\n '@tagreplace.TagReplace': AutoContentProvider\n};\n\n// TODO: Implement TagReplace\nAutoContentProvider.registerClass('@tagreplace.TagReplace', AutoContentProvider);\n\nexport default AutoContentProvider;\n"],"names":[],"sourceRoot":""}
@@ -1,450 +0,0 @@
1
- "use strict";
2
- exports.id = 2437;
3
- exports.ids = [2437];
4
- exports.modules = {
5
-
6
- /***/ 2437:
7
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
8
-
9
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
10
- /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
11
- /* harmony export */ });
12
- /* unused harmony exports FillInBlanks, FillInBlanksPanel */
13
- /* harmony import */ var _Activity_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1567);
14
- /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7750);
15
- /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_1__);
16
- /* harmony import */ var _Utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1253);
17
- /* harmony import */ var _TextActivityBase_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(743);
18
- /**
19
- * File : activities/text/FillInBlanks.js
20
- * Created : 20/06/2015
21
- * By : Francesc Busquets <francesc@gmail.com>
22
- *
23
- * JClic.js
24
- * An HTML5 player of JClic activities
25
- * https://projectestac.github.io/jclic.js
26
- *
27
- * @source https://github.com/projectestac/jclic.js
28
- *
29
- * @license EUPL-1.2
30
- * @licstart
31
- * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)
32
- *
33
- * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by
34
- * the European Commission- subsequent versions of the EUPL (the "Licence");
35
- * You may not use this work except in compliance with the Licence.
36
- *
37
- * You may obtain a copy of the Licence at:
38
- * https://joinup.ec.europa.eu/software/page/eupl
39
- *
40
- * Unless required by applicable law or agreed to in writing, software
41
- * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
42
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
43
- * Licence for the specific language governing permissions and limitations
44
- * under the Licence.
45
- * @licend
46
- * @module
47
- */
48
-
49
-
50
-
51
-
52
-
53
-
54
- /**
55
- * In this type of activity the text document has some blanks that must be filled-in. The blanks
56
- * can be drop-down boxes or text fields (empty or pre-filled with an initial text). Blanks can
57
- * also have associated clues, shown as "pop-ups".
58
- * @extends module:activities/text/TextActivityBase.TextActivityBase
59
- */
60
- class FillInBlanks extends _TextActivityBase_js__WEBPACK_IMPORTED_MODULE_3__/* .TextActivityBase */ .q {
61
- /**
62
- * FillInBlanks constructor
63
- * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs
64
- */
65
- constructor(project) {
66
- super(project);
67
- }
68
-
69
- /**
70
- * This kind of activity usually makes use of the keyboard
71
- * @override
72
- * @returns {boolean}
73
- */
74
- needsKeyboard() {
75
- return true;
76
- }
77
- }
78
-
79
- Object.assign(FillInBlanks.prototype, {
80
- /**
81
- * Whether to jump or not to the next target when the current one is solved.
82
- * @name module:activities/text/FillInBlanks.FillInBlanks#autoJump
83
- * @type {boolean} */
84
- autoJump: false,
85
- /**
86
- * Whether to block or not the jump to other targets until the current one
87
- * is resolved.
88
- * @name module:activities/text/FillInBlanks.FillInBlanks#forceOkToAdvance
89
- * @type {boolean} */
90
- forceOkToAdvance: false,
91
- });
92
-
93
- /**
94
- * The {@link module:activities/text/TextActivityBase.TextActivityBasePanel} where {@link module:activities/text/FillInBlanks.FillInBlanks FillInBlanks} activities are played.
95
- * @extends module:activities/text/TextActivityBase.TextActivityBasePanel
96
- */
97
- class FillInBlanksPanel extends _TextActivityBase_js__WEBPACK_IMPORTED_MODULE_3__/* .TextActivityBasePanel */ .c {
98
- /**
99
- * FillInBlanksPanel constructor
100
- * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs
101
- * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the
102
- * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.
103
- * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy
104
- */
105
- constructor(act, ps, $div) {
106
- super(act, ps, $div);
107
- }
108
-
109
- /**
110
- * Creates a target DOM element for the provided target. This DOM element can be an editable
111
- * `span` or a `select` with specific `option` elements (when the target is a drop-down list)
112
- * @override
113
- * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created
114
- * @param {external:jQuery} $span - - An initial DOM object (usually a `span`) that can be used
115
- * to store the target, or replaced by another type of object.
116
- * @returns {external:jQuery} - The jQuery DOM element loaded with the target data.
117
- */
118
- $createTargetElement(target, $span) {
119
-
120
- $span.addClass('JClicTextTarget');
121
-
122
- const idLabel = `target${`000${this.targets.length - 1}`.slice(-3)}`;
123
- if (target.isList && target.options && target.options.length > 0) {
124
- // Use a `select` element
125
- $span = jquery__WEBPACK_IMPORTED_MODULE_1___default()('<select/>', { id: idLabel, name: idLabel });
126
- if (target.options[0].trim() !== '')
127
- jquery__WEBPACK_IMPORTED_MODULE_1___default()('<option selected/>', { value: '', text: '' }).appendTo($span);
128
- target.options.forEach(op => jquery__WEBPACK_IMPORTED_MODULE_1___default()('<option/>', { value: op, text: op }).appendTo($span));
129
- target.$comboList = $span.bind('focus change', event => {
130
- event.textTarget = target;
131
- this.processEvent(event);
132
- });
133
- } else {
134
- // Use a `span` element with the `contentEditable` attribute set `on`
135
- target.currentText = target.iniText ?
136
- target.iniText
137
- : (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .fillString */ .vD)(target.iniChar, target.numIniChars);
138
-
139
- target.$span = $span.text(target.currentText).attr({
140
- contenteditable: 'true',
141
- id: idLabel,
142
- autocomplete: 'off',
143
- spellcheck: 'false'
144
- }).bind('focus input blur', event => {
145
- event.textTarget = target;
146
- this.processEvent(event);
147
- }).bind('keydown keyup', event => {
148
- // Catch `enter` key in Firefox
149
- if (event.keyCode === 13) {
150
- event.preventDefault();
151
- if (event.type === 'keydown') {
152
- // Simulate a `blur` event
153
- event.textTarget = target;
154
- event.type = 'blur';
155
- this.processEvent(event);
156
- }
157
- }
158
- });
159
- }
160
- return $span;
161
- }
162
-
163
- /**
164
- * Evaluates all the targets in this panel. This method is usually called from the `Check` button.
165
- * @override
166
- * @returns {boolean} - `true` when all targets are OK, `false` otherwise.
167
- */
168
- evaluatePanel() {
169
- let targetsOk = 0;
170
- const numTargets = this.targets.length;
171
- this.targets.forEach(target => {
172
- const
173
- result = this.act.ev.evalText(target.readCurrentText(), target.answers),
174
- ok = this.act.ev.isOk(result);
175
- target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';
176
- if (ok)
177
- targetsOk++;
178
- this.markTarget(target, result);
179
- this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);
180
- });
181
- if (targetsOk === numTargets) {
182
- this.finishActivity(true);
183
- return true;
184
- } else
185
- this.playEvent('finishedError');
186
- return false;
187
- }
188
-
189
- /**
190
- * Checks if the specified TextTarget has a valid answer in its `currentText` field
191
- * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target to check
192
- * @param {boolean} onlyCheck - When `true`, the cursor will no be re-positioned
193
- * @param {number} [jumpDirection] - `1` to go forward, `-1` to go back.
194
- * @returns {boolean} - `true` when the target contains a valid answer
195
- */
196
- checkTarget(target, onlyCheck, jumpDirection) {
197
- const
198
- result = this.act.ev.evalText(target.currentText, target.answers),
199
- ok = this.act.ev.isOk(result);
200
-
201
- target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';
202
- if (onlyCheck)
203
- return ok;
204
-
205
- this.markTarget(target, result);
206
- const targetsOk = this.countSolvedTargets(false, false);
207
- if (target.currentText.length > 0)
208
- this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);
209
- if (ok && targetsOk === this.targets.length) {
210
- this.finishActivity(true);
211
- return ok;
212
- } else if (target.currentText.length > 0)
213
- this.playEvent(ok ? 'actionOk' : 'actionError');
214
-
215
- if (jumpDirection && jumpDirection !== 0) {
216
- let p = target.num + jumpDirection;
217
- if (p >= this.targets.length)
218
- p = 0;
219
- else if (p < 0)
220
- p = this.targets.length - 1;
221
-
222
- const destTarget = this.targets[p];
223
- if (destTarget.$span) {
224
- destTarget.$span.focus();
225
- (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .setSelectionRange */ .eG)(destTarget.$span.get(-1), 0, 0);
226
- } else if (destTarget.$comboList)
227
- destTarget.$comboList.focus();
228
- }
229
- return ok;
230
- }
231
-
232
- /**
233
- * Counts the number of targets with `SOLVED` status
234
- * @param {boolean} checkNow - When `true`, all targets will be evaluated. Otherwise, only the
235
- * current value of `targetStatus` will be checked.
236
- * @param {boolean} [mark] - When `true`, errors in the target answer will be marked.
237
- * @returns {number} - The number of targets currently solved.
238
- */
239
- countSolvedTargets(checkNow, mark) {
240
- return this.targets.reduce((n, target) => {
241
- if (checkNow) {
242
- target.readCurrentText();
243
- this.checkTarget(target, !mark);
244
- }
245
- return target.targetStatus === 'SOLVED' ? ++n : n;
246
- }, 0);
247
- }
248
-
249
- /**
250
- * Visually marks the target as 'solved OK' or 'with errors'.
251
- * @param {module:activities/text/TextActivityDocument.TextTarget} target - The text target to be marked.
252
- * @param {number[]} attributes - - Array of flags indicating the status (OK or error) for each
253
- * character in `target.currentText`.
254
- */
255
- markTarget(target, attributes) {
256
- if (target.$comboList || this.act.ev.isOk(attributes))
257
- target.checkColors();
258
- else if (target.$span) {
259
- // Identify text fragments
260
- const
261
- txt = target.currentText,
262
- fragments = [];
263
- let
264
- currentStatus = -1,
265
- currentFragment = -1,
266
- i = 0;
267
- for (; i < attributes.length && i < txt.length; i++) {
268
- if (attributes[i] !== currentStatus) {
269
- fragments[++currentFragment] = '';
270
- currentStatus = attributes[i];
271
- }
272
- fragments[currentFragment] += txt.charAt(i);
273
- }
274
- if (i < txt.length)
275
- fragments[currentFragment] += txt.substring(i);
276
- // Empty and re-fill $span
277
- target.$span.empty();
278
- currentStatus = attributes[0];
279
- fragments.forEach(fragment => {
280
- jquery__WEBPACK_IMPORTED_MODULE_1___default()('<span/>')
281
- .text(fragment)
282
- .css(target.doc.style[currentStatus === 0 ? 'target' : 'targetError'].css)
283
- .appendTo(target.$span);
284
- currentStatus ^= 1;
285
- });
286
- }
287
- // Target has been marked, so clear the 'modified' flag
288
- target.flagModified = false;
289
- }
290
-
291
- /**
292
- * Called by {@link module:JClicPlayer.JClicPlayer JClicPlayer} when this activity panel is fully visible, just after the
293
- * initialization process.
294
- * @override
295
- */
296
- activityReady() {
297
- super.activityReady();
298
-
299
- // Prevent strange behavior with GoogleChrome when `white-space` CSS attribute is set to
300
- // `pre-wrap` (needed for tabulated texts)
301
- jquery__WEBPACK_IMPORTED_MODULE_1___default()('.JClicTextTarget').css('white-space', 'normal');
302
- if (this.targets.length > 0 && this.targets[0].$span)
303
- this.targets[0].$span.focus();
304
- }
305
-
306
- /**
307
- * Ordinary ending of the activity, usually called form `processEvent`
308
- * @override
309
- * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise
310
- */
311
- finishActivity(result) {
312
- this.targets.forEach(target => {
313
- if (target.$span)
314
- target.$span.removeAttr('contenteditable').blur();
315
- else if (target.$comboList)
316
- target.$comboList.attr('disabled', 'true').blur();
317
- });
318
- return super.finishActivity(result);
319
- }
320
-
321
- /**
322
- * Main handler used to process mouse, touch, keyboard and edit events.
323
- * @override
324
- * @param {external:Event} event - The HTML event to be processed
325
- * @returns {boolean} - When this event handler returns `false`, jQuery will stop its
326
- * propagation through the DOM tree. See: {@link http://api.jquery.com/on}
327
- */
328
- processEvent(event) {
329
- if (!super.processEvent(event))
330
- return false;
331
-
332
- const target = event.textTarget;
333
- let $span = null, pos = 0;
334
- switch (event.type) {
335
- case 'focus':
336
- if (target) {
337
- if (target.$span && target.$span.children().length > 0) {
338
- // Clear inner spans used to mark errors
339
- $span = target.$span;
340
- pos = Math.min(
341
- target.currentText.length,
342
- (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .getCaretCharacterOffsetWithin */ .Hb)($span.get(-1)));
343
- $span.empty();
344
- $span.text(target.currentText);
345
- (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .setSelectionRange */ .eG)($span.get(-1), pos, pos);
346
- target.flagModified = true;
347
- } else if (target.$comboList)
348
- target.$comboList.css(target.doc.style['target'].css);
349
-
350
- if (target.$popup && (target.infoMode === 'always' || target.infoMode === 'onError' && target.targetStatus === 'WITH_ERROR'))
351
- this.showPopup(target.$popup, target.popupMaxTime, target.popupDelay);
352
- else
353
- this.showPopup(null);
354
- }
355
- break;
356
-
357
- case 'blur':
358
- if (target.flagModified && !this.$checkButton)
359
- this.checkTarget(target, false, 1);
360
- break;
361
-
362
- case 'input':
363
- if (target && target.$span) {
364
- $span = target.$span;
365
- let txt = $span.html();
366
- // Check for `enter` key
367
- if (/(<br>|\n|\r)/.test(txt)) {
368
- txt = txt.replace(/(<br>|\n|\r)/g, '');
369
- $span.html(txt);
370
- target.currentText = $span.text();
371
- return this.$checkButton ? false : this.checkTarget(target, false, 1);
372
- }
373
- // Check if text has changed
374
- // From here, use 'text' instead of 'html' to avoid HTML entities
375
- txt = $span.text();
376
- if (txt !== target.currentText) {
377
- // Span text has changed!
378
- target.flagModified = true;
379
- const added = txt.length - target.currentText.length;
380
- if (added > 0) {
381
- if (txt.indexOf(target.iniChar) >= 0) {
382
- // Remove filling chars
383
- pos = (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .getCaretCharacterOffsetWithin */ .Hb)($span.get(-1));
384
- for (let i = 0; i < added; i++) {
385
- const p = txt.indexOf(target.iniChar);
386
- if (p < 0)
387
- break;
388
- txt = txt.substring(0, p) + txt.substring(p + 1);
389
- if (p < pos)
390
- pos--;
391
- }
392
- $span.text(txt);
393
- (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .setSelectionRange */ .eG)($span.get(-1), pos, pos);
394
- }
395
-
396
- // Check if current text exceeds max length
397
- if (txt.length > target.maxLenResp) {
398
- pos = (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .getCaretCharacterOffsetWithin */ .Hb)($span.get(-1));
399
- txt = txt.substring(0, target.maxLenResp);
400
- pos = Math.min(pos, txt.length);
401
- $span.text(txt);
402
- (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .setSelectionRange */ .eG)($span.get(-1), pos, pos);
403
- }
404
- } else if (txt === '') {
405
- txt = target.iniChar;
406
- $span.text(txt);
407
- (0,_Utils_js__WEBPACK_IMPORTED_MODULE_2__/* .setSelectionRange */ .eG)($span.get(-1), 0, 0);
408
- }
409
- target.currentText = txt;
410
- }
411
- }
412
- break;
413
-
414
- case 'change':
415
- if (target && target.$comboList) {
416
- target.currentText = target.$comboList.val();
417
- target.flagModified = true;
418
- return this.$checkButton ? false : this.checkTarget(target, false, 1);
419
- }
420
- break;
421
-
422
- default:
423
- break;
424
- }
425
- return true;
426
- }
427
- }
428
-
429
- Object.assign(FillInBlanksPanel.prototype, {
430
- /**
431
- * Flag indicating if the activity is open or locked
432
- * @name module:activities/text/FillInBlanks.FillInBlanksPanel#locked
433
- * @type {boolean} */
434
- locked: true,
435
- });
436
-
437
- /**
438
- * Panel class associated to this type of activity: {@link module:activities/text/FillInBlanks.FillInBlanksPanel FillInBlanksPanel}
439
- * @type {class} */
440
- FillInBlanks.Panel = FillInBlanksPanel;
441
-
442
- // Register activity class
443
- /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_Activity_js__WEBPACK_IMPORTED_MODULE_0__["default"].registerClass('@text.FillInBlanks', FillInBlanks));
444
-
445
-
446
- /***/ })
447
-
448
- };
449
- ;
450
- //# sourceMappingURL=2437.jclic-node.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"2437.jclic-node.js","mappings":";;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEyC;AAClB;AACuE;AACd;;AAEhF;AACA;AACA;AACA;AACA;AACA;AACO,2BAA2B,2EAAgB;AAClD;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,QAAQ,qEAAqE,OAAO,qEAAqE;AACzJ;AACA;AACO,gCAAgC,gFAAqB;AAC5D;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,iBAAiB;AAC9B;AACA,eAAe,iBAAiB;AAChC;AACA;;AAEA;;AAEA,6BAA6B,MAAM,wBAAwB,YAAY;AACvE;AACA;AACA,cAAc,6CAAC,gBAAgB,4BAA4B;AAC3D;AACA,QAAQ,6CAAC,yBAAyB,qBAAqB;AACvD,mCAAmC,6CAAC,gBAAgB,qBAAqB;AACzE;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA,UAAU,+DAAU;;AAEpB;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,SAAS;AACtB,aAAa,QAAQ;AACrB,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ,sEAAiB;AACzB,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA,aAAa,SAAS;AACtB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,UAAU;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,yCAAyC;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,6CAAC;AACT;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,kDAAkD;AAClE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI,6CAAC;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,kFAA6B;AAC3C;AACA;AACA,YAAY,sEAAiB;AAC7B;AACA,YAAY;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,kFAA6B;AACnD,gCAAgC,WAAW;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,sEAAiB;AACjC;;AAEA;AACA;AACA,sBAAsB,kFAA6B;AACnD;AACA;AACA;AACA,gBAAgB,sEAAiB;AACjC;AACA,cAAc;AACd;AACA;AACA,cAAc,sEAAiB;AAC/B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,iEAAe,oDAAQ,kDAAkD,EAAC","sources":["webpack://jclic/./src/activities/text/FillInBlanks.js"],"sourcesContent":["/**\n * File : activities/text/FillInBlanks.js\n * Created : 20/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Activity from '../../Activity.js';\nimport $ from 'jquery';\nimport { fillString, setSelectionRange, getCaretCharacterOffsetWithin } from '../../Utils.js';\nimport { TextActivityBase, TextActivityBasePanel } from './TextActivityBase.js';\n\n/**\n * In this type of activity the text document has some blanks that must be filled-in. The blanks\n * can be drop-down boxes or text fields (empty or pre-filled with an initial text). Blanks can\n * also have associated clues, shown as \"pop-ups\".\n * @extends module:activities/text/TextActivityBase.TextActivityBase\n */\nexport class FillInBlanks extends TextActivityBase {\n /**\n * FillInBlanks constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * This kind of activity usually makes use of the keyboard\n * @override\n * @returns {boolean}\n */\n needsKeyboard() {\n return true;\n }\n}\n\nObject.assign(FillInBlanks.prototype, {\n /**\n * Whether to jump or not to the next target when the current one is solved.\n * @name module:activities/text/FillInBlanks.FillInBlanks#autoJump\n * @type {boolean} */\n autoJump: false,\n /**\n * Whether to block or not the jump to other targets until the current one\n * is resolved.\n * @name module:activities/text/FillInBlanks.FillInBlanks#forceOkToAdvance\n * @type {boolean} */\n forceOkToAdvance: false,\n});\n\n/**\n * The {@link module:activities/text/TextActivityBase.TextActivityBasePanel} where {@link module:activities/text/FillInBlanks.FillInBlanks FillInBlanks} activities are played.\n * @extends module:activities/text/TextActivityBase.TextActivityBasePanel\n */\nexport class FillInBlanksPanel extends TextActivityBasePanel {\n /**\n * FillInBlanksPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Creates a target DOM element for the provided target. This DOM element can be an editable\n * `span` or a `select` with specific `option` elements (when the target is a drop-down list)\n * @override\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created\n * @param {external:jQuery} $span - - An initial DOM object (usually a `span`) that can be used\n * to store the target, or replaced by another type of object.\n * @returns {external:jQuery} - The jQuery DOM element loaded with the target data.\n */\n $createTargetElement(target, $span) {\n\n $span.addClass('JClicTextTarget');\n\n const idLabel = `target${`000${this.targets.length - 1}`.slice(-3)}`;\n if (target.isList && target.options && target.options.length > 0) {\n // Use a `select` element\n $span = $('<select/>', { id: idLabel, name: idLabel });\n if (target.options[0].trim() !== '')\n $('<option selected/>', { value: '', text: '' }).appendTo($span);\n target.options.forEach(op => $('<option/>', { value: op, text: op }).appendTo($span));\n target.$comboList = $span.bind('focus change', event => {\n event.textTarget = target;\n this.processEvent(event);\n });\n } else {\n // Use a `span` element with the `contentEditable` attribute set `on`\n target.currentText = target.iniText ?\n target.iniText\n : fillString(target.iniChar, target.numIniChars);\n\n target.$span = $span.text(target.currentText).attr({\n contenteditable: 'true',\n id: idLabel,\n autocomplete: 'off',\n spellcheck: 'false'\n }).bind('focus input blur', event => {\n event.textTarget = target;\n this.processEvent(event);\n }).bind('keydown keyup', event => {\n // Catch `enter` key in Firefox\n if (event.keyCode === 13) {\n event.preventDefault();\n if (event.type === 'keydown') {\n // Simulate a `blur` event\n event.textTarget = target;\n event.type = 'blur';\n this.processEvent(event);\n }\n }\n });\n }\n return $span;\n }\n\n /**\n * Evaluates all the targets in this panel. This method is usually called from the `Check` button.\n * @override\n * @returns {boolean} - `true` when all targets are OK, `false` otherwise.\n */\n evaluatePanel() {\n let targetsOk = 0;\n const numTargets = this.targets.length;\n this.targets.forEach(target => {\n const\n result = this.act.ev.evalText(target.readCurrentText(), target.answers),\n ok = this.act.ev.isOk(result);\n target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';\n if (ok)\n targetsOk++;\n this.markTarget(target, result);\n this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);\n });\n if (targetsOk === numTargets) {\n this.finishActivity(true);\n return true;\n } else\n this.playEvent('finishedError');\n return false;\n }\n\n /**\n * Checks if the specified TextTarget has a valid answer in its `currentText` field\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target to check\n * @param {boolean} onlyCheck - When `true`, the cursor will no be re-positioned\n * @param {number} [jumpDirection] - `1` to go forward, `-1` to go back.\n * @returns {boolean} - `true` when the target contains a valid answer\n */\n checkTarget(target, onlyCheck, jumpDirection) {\n const\n result = this.act.ev.evalText(target.currentText, target.answers),\n ok = this.act.ev.isOk(result);\n\n target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';\n if (onlyCheck)\n return ok;\n\n this.markTarget(target, result);\n const targetsOk = this.countSolvedTargets(false, false);\n if (target.currentText.length > 0)\n this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);\n if (ok && targetsOk === this.targets.length) {\n this.finishActivity(true);\n return ok;\n } else if (target.currentText.length > 0)\n this.playEvent(ok ? 'actionOk' : 'actionError');\n\n if (jumpDirection && jumpDirection !== 0) {\n let p = target.num + jumpDirection;\n if (p >= this.targets.length)\n p = 0;\n else if (p < 0)\n p = this.targets.length - 1;\n\n const destTarget = this.targets[p];\n if (destTarget.$span) {\n destTarget.$span.focus();\n setSelectionRange(destTarget.$span.get(-1), 0, 0);\n } else if (destTarget.$comboList)\n destTarget.$comboList.focus();\n }\n return ok;\n }\n\n /**\n * Counts the number of targets with `SOLVED` status\n * @param {boolean} checkNow - When `true`, all targets will be evaluated. Otherwise, only the\n * current value of `targetStatus` will be checked.\n * @param {boolean} [mark] - When `true`, errors in the target answer will be marked.\n * @returns {number} - The number of targets currently solved.\n */\n countSolvedTargets(checkNow, mark) {\n return this.targets.reduce((n, target) => {\n if (checkNow) {\n target.readCurrentText();\n this.checkTarget(target, !mark);\n }\n return target.targetStatus === 'SOLVED' ? ++n : n;\n }, 0);\n }\n\n /**\n * Visually marks the target as 'solved OK' or 'with errors'.\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The text target to be marked.\n * @param {number[]} attributes - - Array of flags indicating the status (OK or error) for each\n * character in `target.currentText`.\n */\n markTarget(target, attributes) {\n if (target.$comboList || this.act.ev.isOk(attributes))\n target.checkColors();\n else if (target.$span) {\n // Identify text fragments\n const\n txt = target.currentText,\n fragments = [];\n let\n currentStatus = -1,\n currentFragment = -1,\n i = 0;\n for (; i < attributes.length && i < txt.length; i++) {\n if (attributes[i] !== currentStatus) {\n fragments[++currentFragment] = '';\n currentStatus = attributes[i];\n }\n fragments[currentFragment] += txt.charAt(i);\n }\n if (i < txt.length)\n fragments[currentFragment] += txt.substring(i);\n // Empty and re-fill $span\n target.$span.empty();\n currentStatus = attributes[0];\n fragments.forEach(fragment => {\n $('<span/>')\n .text(fragment)\n .css(target.doc.style[currentStatus === 0 ? 'target' : 'targetError'].css)\n .appendTo(target.$span);\n currentStatus ^= 1;\n });\n }\n // Target has been marked, so clear the 'modified' flag\n target.flagModified = false;\n }\n\n /**\n * Called by {@link module:JClicPlayer.JClicPlayer JClicPlayer} when this activity panel is fully visible, just after the\n * initialization process.\n * @override\n */\n activityReady() {\n super.activityReady();\n\n // Prevent strange behavior with GoogleChrome when `white-space` CSS attribute is set to\n // `pre-wrap` (needed for tabulated texts)\n $('.JClicTextTarget').css('white-space', 'normal');\n if (this.targets.length > 0 && this.targets[0].$span)\n this.targets[0].$span.focus();\n }\n\n /**\n * Ordinary ending of the activity, usually called form `processEvent`\n * @override\n * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise\n */\n finishActivity(result) {\n this.targets.forEach(target => {\n if (target.$span)\n target.$span.removeAttr('contenteditable').blur();\n else if (target.$comboList)\n target.$comboList.attr('disabled', 'true').blur();\n });\n return super.finishActivity(result);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events.\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (!super.processEvent(event))\n return false;\n\n const target = event.textTarget;\n let $span = null, pos = 0;\n switch (event.type) {\n case 'focus':\n if (target) {\n if (target.$span && target.$span.children().length > 0) {\n // Clear inner spans used to mark errors\n $span = target.$span;\n pos = Math.min(\n target.currentText.length,\n getCaretCharacterOffsetWithin($span.get(-1)));\n $span.empty();\n $span.text(target.currentText);\n setSelectionRange($span.get(-1), pos, pos);\n target.flagModified = true;\n } else if (target.$comboList)\n target.$comboList.css(target.doc.style['target'].css);\n\n if (target.$popup && (target.infoMode === 'always' || target.infoMode === 'onError' && target.targetStatus === 'WITH_ERROR'))\n this.showPopup(target.$popup, target.popupMaxTime, target.popupDelay);\n else\n this.showPopup(null);\n }\n break;\n\n case 'blur':\n if (target.flagModified && !this.$checkButton)\n this.checkTarget(target, false, 1);\n break;\n\n case 'input':\n if (target && target.$span) {\n $span = target.$span;\n let txt = $span.html();\n // Check for `enter` key\n if (/(<br>|\\n|\\r)/.test(txt)) {\n txt = txt.replace(/(<br>|\\n|\\r)/g, '');\n $span.html(txt);\n target.currentText = $span.text();\n return this.$checkButton ? false : this.checkTarget(target, false, 1);\n }\n // Check if text has changed\n // From here, use 'text' instead of 'html' to avoid HTML entities\n txt = $span.text();\n if (txt !== target.currentText) {\n // Span text has changed!\n target.flagModified = true;\n const added = txt.length - target.currentText.length;\n if (added > 0) {\n if (txt.indexOf(target.iniChar) >= 0) {\n // Remove filling chars\n pos = getCaretCharacterOffsetWithin($span.get(-1));\n for (let i = 0; i < added; i++) {\n const p = txt.indexOf(target.iniChar);\n if (p < 0)\n break;\n txt = txt.substring(0, p) + txt.substring(p + 1);\n if (p < pos)\n pos--;\n }\n $span.text(txt);\n setSelectionRange($span.get(-1), pos, pos);\n }\n\n // Check if current text exceeds max length\n if (txt.length > target.maxLenResp) {\n pos = getCaretCharacterOffsetWithin($span.get(-1));\n txt = txt.substring(0, target.maxLenResp);\n pos = Math.min(pos, txt.length);\n $span.text(txt);\n setSelectionRange($span.get(-1), pos, pos);\n }\n } else if (txt === '') {\n txt = target.iniChar;\n $span.text(txt);\n setSelectionRange($span.get(-1), 0, 0);\n }\n target.currentText = txt;\n }\n }\n break;\n\n case 'change':\n if (target && target.$comboList) {\n target.currentText = target.$comboList.val();\n target.flagModified = true;\n return this.$checkButton ? false : this.checkTarget(target, false, 1);\n }\n break;\n\n default:\n break;\n }\n return true;\n }\n}\n\nObject.assign(FillInBlanksPanel.prototype, {\n /**\n * Flag indicating if the activity is open or locked\n * @name module:activities/text/FillInBlanks.FillInBlanksPanel#locked\n * @type {boolean} */\n locked: true,\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/text/FillInBlanks.FillInBlanksPanel FillInBlanksPanel}\n * @type {class} */\nFillInBlanks.Panel = FillInBlanksPanel;\n\n// Register activity class\nexport default Activity.registerClass('@text.FillInBlanks', FillInBlanks);\n"],"names":[],"sourceRoot":""}