jclic 2.1.21 → 2.1.22
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/CHANGELOG.md +4 -0
- package/dist/jclic-node.js +1 -1
- package/dist/jclic-node.js.map +1 -1
- package/dist/jclic.min.js +2 -2
- package/dist/jclic.min.js.map +1 -1
- package/package.json +1 -1
- package/src/GlobalData.js +1 -1
- package/dist/1078.jclic-node.js +0 -282
- package/dist/1078.jclic-node.js.map +0 -1
- package/dist/1196.jclic-node.js +0 -808
- package/dist/1196.jclic-node.js.map +0 -1
- package/dist/1253.jclic-node.js +0 -1432
- package/dist/1253.jclic-node.js.map +0 -1
- package/dist/13.jclic-node.js +0 -103
- package/dist/13.jclic-node.js.map +0 -1
- package/dist/1567.jclic-node.js +0 -2313
- package/dist/1567.jclic-node.js.map +0 -1
- package/dist/1588.jclic-node.js +0 -602
- package/dist/1588.jclic-node.js.map +0 -1
- package/dist/1725.jclic-node.js +0 -836
- package/dist/1725.jclic-node.js.map +0 -1
- package/dist/1731.jclic-node.js +0 -438
- package/dist/1731.jclic-node.js.map +0 -1
- package/dist/1842.jclic-node.js +0 -651
- package/dist/1842.jclic-node.js.map +0 -1
- package/dist/2160.jclic-node.js +0 -1016
- package/dist/2160.jclic-node.js.map +0 -1
- package/dist/222.jclic-node.js +0 -129
- package/dist/222.jclic-node.js.map +0 -1
- package/dist/2316.jclic-node.js +0 -949
- package/dist/2316.jclic-node.js.map +0 -1
- package/dist/2355.jclic-node.js +0 -371
- package/dist/2355.jclic-node.js.map +0 -1
- package/dist/2366.jclic-node.js +0 -431
- package/dist/2366.jclic-node.js.map +0 -1
- package/dist/2379.jclic-node.js +0 -202
- package/dist/2379.jclic-node.js.map +0 -1
- package/dist/2437.jclic-node.js +0 -450
- package/dist/2437.jclic-node.js.map +0 -1
- package/dist/2531.jclic-node.js +0 -869
- package/dist/2531.jclic-node.js.map +0 -1
- package/dist/2608.jclic-node.js +0 -160
- package/dist/2608.jclic-node.js.map +0 -1
- package/dist/2715.jclic-node.js +0 -554
- package/dist/2715.jclic-node.js.map +0 -1
- package/dist/277.jclic-node.js +0 -22
- package/dist/277.jclic-node.js.map +0 -1
- package/dist/2921.jclic-node.js +0 -660
- package/dist/2921.jclic-node.js.map +0 -1
- package/dist/2952.jclic-node.js +0 -101
- package/dist/2952.jclic-node.js.map +0 -1
- package/dist/3018.jclic-node.js +0 -421
- package/dist/3018.jclic-node.js.map +0 -1
- package/dist/3019.jclic-node.js +0 -682
- package/dist/3019.jclic-node.js.map +0 -1
- package/dist/3231.jclic-node.js +0 -274
- package/dist/3231.jclic-node.js.map +0 -1
- package/dist/331.jclic-node.js +0 -115
- package/dist/331.jclic-node.js.map +0 -1
- package/dist/3391.jclic-node.js +0 -276
- package/dist/3391.jclic-node.js.map +0 -1
- package/dist/3502.jclic-node.js +0 -671
- package/dist/3502.jclic-node.js.map +0 -1
- package/dist/3653.jclic-node.js +0 -982
- package/dist/3653.jclic-node.js.map +0 -1
- package/dist/371.jclic.min.js +0 -2
- package/dist/371.jclic.min.js.map +0 -1
- package/dist/3856.jclic-node.js +0 -575
- package/dist/3856.jclic-node.js.map +0 -1
- package/dist/4112.jclic-node.js +0 -659
- package/dist/4112.jclic-node.js.map +0 -1
- package/dist/4123.jclic-node.js +0 -910
- package/dist/4123.jclic-node.js.map +0 -1
- package/dist/427.jclic-node.js +0 -894
- package/dist/427.jclic-node.js.map +0 -1
- package/dist/4483.jclic-node.js +0 -327
- package/dist/4483.jclic-node.js.map +0 -1
- package/dist/4548.jclic-node.js +0 -1078
- package/dist/4548.jclic-node.js.map +0 -1
- package/dist/466.jclic-node.js +0 -99
- package/dist/466.jclic-node.js.map +0 -1
- package/dist/485.jclic-node.js +0 -783
- package/dist/485.jclic-node.js.map +0 -1
- package/dist/4921.jclic-node.js +0 -500
- package/dist/4921.jclic-node.js.map +0 -1
- package/dist/5091.jclic-node.js +0 -239
- package/dist/5091.jclic-node.js.map +0 -1
- package/dist/520.jclic-node.js +0 -550
- package/dist/520.jclic-node.js.map +0 -1
- package/dist/5312.jclic-node.js +0 -1126
- package/dist/5312.jclic-node.js.map +0 -1
- package/dist/5338.jclic-node.js +0 -212
- package/dist/5338.jclic-node.js.map +0 -1
- package/dist/5344.jclic-node.js +0 -229
- package/dist/5344.jclic-node.js.map +0 -1
- package/dist/5550.jclic-node.js +0 -238
- package/dist/5550.jclic-node.js.map +0 -1
- package/dist/5626.jclic-node.js +0 -614
- package/dist/5626.jclic-node.js.map +0 -1
- package/dist/5977.jclic-node.js +0 -1081
- package/dist/5977.jclic-node.js.map +0 -1
- package/dist/6148.jclic-node.js +0 -345
- package/dist/6148.jclic-node.js.map +0 -1
- package/dist/6176.jclic-node.js +0 -481
- package/dist/6176.jclic-node.js.map +0 -1
- package/dist/6221.jclic-node.js +0 -1072
- package/dist/6221.jclic-node.js.map +0 -1
- package/dist/6238.jclic-node.js +0 -718
- package/dist/6238.jclic-node.js.map +0 -1
- package/dist/6454.jclic-node.js +0 -1413
- package/dist/6454.jclic-node.js.map +0 -1
- package/dist/6565.jclic-node.js +0 -294
- package/dist/6565.jclic-node.js.map +0 -1
- package/dist/6579.jclic-node.js +0 -719
- package/dist/6579.jclic-node.js.map +0 -1
- package/dist/6715.jclic-node.js +0 -148
- package/dist/6715.jclic-node.js.map +0 -1
- package/dist/6777.jclic-node.js +0 -171
- package/dist/6777.jclic-node.js.map +0 -1
- package/dist/6782.jclic-node.js +0 -1611
- package/dist/6782.jclic-node.js.map +0 -1
- package/dist/6847.jclic-node.js +0 -601
- package/dist/6847.jclic-node.js.map +0 -1
- package/dist/6856.jclic-node.js +0 -252
- package/dist/6856.jclic-node.js.map +0 -1
- package/dist/696.jclic-node.js +0 -1821
- package/dist/696.jclic-node.js.map +0 -1
- package/dist/698.jclic-node.js +0 -583
- package/dist/698.jclic-node.js.map +0 -1
- package/dist/704.jclic-node.js +0 -80
- package/dist/704.jclic-node.js.map +0 -1
- package/dist/7046.jclic-node.js +0 -735
- package/dist/7046.jclic-node.js.map +0 -1
- package/dist/7220.jclic-node.js +0 -156
- package/dist/7220.jclic-node.js.map +0 -1
- package/dist/7257.jclic-node.js +0 -931
- package/dist/7257.jclic-node.js.map +0 -1
- package/dist/743.jclic-node.js +0 -583
- package/dist/743.jclic-node.js.map +0 -1
- package/dist/757.jclic-node.js +0 -1072
- package/dist/757.jclic-node.js.map +0 -1
- package/dist/7781.jclic-node.js +0 -202
- package/dist/7781.jclic-node.js.map +0 -1
- package/dist/7912.jclic-node.js +0 -2103
- package/dist/7912.jclic-node.js.map +0 -1
- package/dist/827.jclic-node.js +0 -708
- package/dist/827.jclic-node.js.map +0 -1
- package/dist/8276.jclic-node.js +0 -409
- package/dist/8276.jclic-node.js.map +0 -1
- package/dist/8322.jclic-node.js +0 -498
- package/dist/8322.jclic-node.js.map +0 -1
- package/dist/8641.jclic-node.js +0 -360
- package/dist/8641.jclic-node.js.map +0 -1
- package/dist/8837.jclic-node.js +0 -651
- package/dist/8837.jclic-node.js.map +0 -1
- package/dist/8895.jclic-node.js +0 -151
- package/dist/8895.jclic-node.js.map +0 -1
- package/dist/9072.jclic-node.js +0 -1285
- package/dist/9072.jclic-node.js.map +0 -1
- package/dist/9078.jclic-node.js +0 -935
- package/dist/9078.jclic-node.js.map +0 -1
- package/dist/9103.jclic-node.js +0 -718
- package/dist/9103.jclic-node.js.map +0 -1
- package/dist/9359.jclic-node.js +0 -145
- package/dist/9359.jclic-node.js.map +0 -1
- package/dist/9409.jclic-node.js +0 -921
- package/dist/9409.jclic-node.js.map +0 -1
- package/dist/9513.jclic-node.js +0 -720
- package/dist/9513.jclic-node.js.map +0 -1
- package/dist/9704.jclic-node.js +0 -81
- package/dist/9704.jclic-node.js.map +0 -1
- package/dist/9950.jclic-node.js +0 -827
- package/dist/9950.jclic-node.js.map +0 -1
package/dist/1253.jclic-node.js
DELETED
|
@@ -1,1432 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
exports.id = 1253;
|
|
3
|
-
exports.ids = [1253];
|
|
4
|
-
exports.modules = {
|
|
5
|
-
|
|
6
|
-
/***/ 1253:
|
|
7
|
-
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
8
|
-
|
|
9
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
10
|
-
/* harmony export */ Aj: () => (/* binding */ getRelativePath),
|
|
11
|
-
/* harmony export */ DC: () => (/* binding */ reduceTextsToStrings),
|
|
12
|
-
/* harmony export */ DT: () => (/* binding */ getBasePath),
|
|
13
|
-
/* harmony export */ DV: () => (/* binding */ parseOldDate),
|
|
14
|
-
/* harmony export */ EB: () => (/* binding */ getHMStime),
|
|
15
|
-
/* harmony export */ Fy: () => (/* binding */ parseXmlNode),
|
|
16
|
-
/* harmony export */ GB: () => (/* binding */ roundTo),
|
|
17
|
-
/* harmony export */ GM: () => (/* binding */ attrForEach),
|
|
18
|
-
/* harmony export */ GV: () => (/* binding */ $HTML),
|
|
19
|
-
/* harmony export */ HC: () => (/* binding */ getXmlText),
|
|
20
|
-
/* harmony export */ HR: () => (/* binding */ getImgClipUrl),
|
|
21
|
-
/* harmony export */ H_: () => (/* binding */ getXmlNodeText),
|
|
22
|
-
/* harmony export */ Hb: () => (/* binding */ getCaretCharacterOffsetWithin),
|
|
23
|
-
/* harmony export */ He: () => (/* binding */ setLogLevel),
|
|
24
|
-
/* harmony export */ I4: () => (/* binding */ checkColor),
|
|
25
|
-
/* harmony export */ Im: () => (/* binding */ isEmpty),
|
|
26
|
-
/* harmony export */ Mk: () => (/* binding */ stringToWords),
|
|
27
|
-
/* harmony export */ NQ: () => (/* binding */ getRootHead),
|
|
28
|
-
/* harmony export */ Os: () => (/* binding */ getPercent),
|
|
29
|
-
/* harmony export */ PD: () => (/* binding */ getTriState),
|
|
30
|
-
/* harmony export */ Pj: () => (/* binding */ isNullOrUndef),
|
|
31
|
-
/* harmony export */ Rm: () => (/* binding */ log),
|
|
32
|
-
/* harmony export */ SV: () => (/* binding */ toCssSize),
|
|
33
|
-
/* harmony export */ TQ: () => (/* binding */ findParentsWithChild),
|
|
34
|
-
/* harmony export */ Ts: () => (/* binding */ init),
|
|
35
|
-
/* harmony export */ UM: () => (/* binding */ compareMultipleOptions),
|
|
36
|
-
/* harmony export */ W0: () => (/* binding */ settings),
|
|
37
|
-
/* harmony export */ WZ: () => (/* binding */ getNumber),
|
|
38
|
-
/* harmony export */ Yn: () => (/* binding */ getPath),
|
|
39
|
-
/* harmony export */ bG: () => (/* binding */ cleanOldLanguageTag),
|
|
40
|
-
/* harmony export */ c0: () => (/* binding */ colorHasTransparency),
|
|
41
|
-
/* harmony export */ c4: () => (/* binding */ nSlash),
|
|
42
|
-
/* harmony export */ d5: () => (/* binding */ endsWith),
|
|
43
|
-
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
|
|
44
|
-
/* harmony export */ dw: () => (/* binding */ appendStyleAtHead),
|
|
45
|
-
/* harmony export */ eG: () => (/* binding */ setSelectionRange),
|
|
46
|
-
/* harmony export */ eH: () => (/* binding */ getVal),
|
|
47
|
-
/* harmony export */ fx: () => (/* binding */ fx),
|
|
48
|
-
/* harmony export */ g8: () => (/* binding */ svgToURI),
|
|
49
|
-
/* harmony export */ h2: () => (/* binding */ cloneObject),
|
|
50
|
-
/* harmony export */ iu: () => (/* binding */ getAttr),
|
|
51
|
-
/* harmony export */ k$: () => (/* binding */ isSeparator),
|
|
52
|
-
/* harmony export */ l2: () => (/* binding */ isEquivalent),
|
|
53
|
-
/* harmony export */ ob: () => (/* binding */ setAttr),
|
|
54
|
-
/* harmony export */ pW: () => (/* binding */ getBoolean),
|
|
55
|
-
/* harmony export */ qG: () => (/* binding */ getMsg),
|
|
56
|
-
/* harmony export */ qN: () => (/* binding */ DEFAULT),
|
|
57
|
-
/* harmony export */ r4: () => (/* binding */ getSvg),
|
|
58
|
-
/* harmony export */ vD: () => (/* binding */ fillString),
|
|
59
|
-
/* harmony export */ w1: () => (/* binding */ startsWith),
|
|
60
|
-
/* harmony export */ wF: () => (/* binding */ mReplace),
|
|
61
|
-
/* harmony export */ xw: () => (/* binding */ getPathPromise)
|
|
62
|
-
/* harmony export */ });
|
|
63
|
-
/* unused harmony exports pkg, LOG_LEVELS, LOG_PRINT_LABELS, LOG_OPTIONS, normalizeLocale, checkPreferredLanguage, zp, getDateTime, FALSE, TRUE, cssToString, normalizeObject, getValue, buildObj, isWordDelimiter, isURL, getTextNodesIn, Utils */
|
|
64
|
-
/* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7750);
|
|
65
|
-
/* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);
|
|
66
|
-
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8194);
|
|
67
|
-
/* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_1__);
|
|
68
|
-
/* harmony import */ var jszip_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6402);
|
|
69
|
-
/* harmony import */ var jszip_utils__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(jszip_utils__WEBPACK_IMPORTED_MODULE_2__);
|
|
70
|
-
/* harmony import */ var _GlobalData_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(277);
|
|
71
|
-
/**
|
|
72
|
-
* File : Utils.js
|
|
73
|
-
* Created : 01/04/2015
|
|
74
|
-
* By : Francesc Busquets <francesc@gmail.com>
|
|
75
|
-
*
|
|
76
|
-
* JClic.js
|
|
77
|
-
* An HTML5 player of JClic activities
|
|
78
|
-
* https://projectestac.github.io/jclic.js
|
|
79
|
-
*
|
|
80
|
-
* @source https://github.com/projectestac/jclic.js
|
|
81
|
-
*
|
|
82
|
-
* @license EUPL-1.2
|
|
83
|
-
* @licstart
|
|
84
|
-
* (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)
|
|
85
|
-
*
|
|
86
|
-
* Licensed under the EUPL, Version 1.1 or -as soon they will be approved by
|
|
87
|
-
* the European Commission- subsequent versions of the EUPL (the "Licence");
|
|
88
|
-
* You may not use this work except in compliance with the Licence.
|
|
89
|
-
*
|
|
90
|
-
* You may obtain a copy of the Licence at:
|
|
91
|
-
* https://joinup.ec.europa.eu/software/page/eupl
|
|
92
|
-
*
|
|
93
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
94
|
-
* distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
|
|
95
|
-
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
96
|
-
* Licence for the specific language governing permissions and limitations
|
|
97
|
-
* under the Licence.
|
|
98
|
-
* @licend
|
|
99
|
-
* @module
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
/* global Promise, window, document, console, HTMLElement */
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Exports third-party NPM packages used by JClic, so they become available to other scripts through
|
|
111
|
-
* the global variable `JClicObject` (defined in {@link module:JClic.JClic})
|
|
112
|
-
* @type: {object}
|
|
113
|
-
*/
|
|
114
|
-
const pkg = {
|
|
115
|
-
$: (jquery__WEBPACK_IMPORTED_MODULE_0___default()),
|
|
116
|
-
JSZip: (jszip__WEBPACK_IMPORTED_MODULE_1___default()),
|
|
117
|
-
JSZipUtils: (jszip_utils__WEBPACK_IMPORTED_MODULE_2___default()),
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* List of valid verbosity levels
|
|
122
|
-
* @const {string[]}
|
|
123
|
-
*/
|
|
124
|
-
const LOG_LEVELS = ['none', 'error', 'warn', 'info', 'debug', 'trace', 'all'];
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Labels printed on logs for each message type
|
|
128
|
-
* @const {string[]}
|
|
129
|
-
*/
|
|
130
|
-
const LOG_PRINT_LABELS = [' ', 'ERROR', 'WARN ', 'INFO ', 'DEBUG', 'TRACE', 'ALL '];
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Options of the logging system
|
|
134
|
-
* @type {object} */
|
|
135
|
-
const LOG_OPTIONS = {
|
|
136
|
-
level: 2, // warn
|
|
137
|
-
prefix: 'JClic',
|
|
138
|
-
timestamp: true,
|
|
139
|
-
popupOnErrors: false,
|
|
140
|
-
chainTo: null,
|
|
141
|
-
pipeTo: null,
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Current dictionary of string translations
|
|
146
|
-
*/
|
|
147
|
-
let _messages = {};
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Initializes the global settings
|
|
151
|
-
* @param {object} options - An object with global settings
|
|
152
|
-
* @param {boolean} [setLog=true] - When `true`, the log level will be set
|
|
153
|
-
* @param {boolean} [setLang=true] - When `true`, the current language will be set
|
|
154
|
-
* @returns {object} The normalized `options` object
|
|
155
|
-
*/
|
|
156
|
-
function init(options, setLog = true, setLang = true) {
|
|
157
|
-
options = normalizeObject(options);
|
|
158
|
-
if (setLog) {
|
|
159
|
-
if (typeof options.logLevel !== 'undefined')
|
|
160
|
-
setLogLevel(options.logLevel);
|
|
161
|
-
if (typeof options.chainLogTo === 'function')
|
|
162
|
-
LOG_OPTIONS.chainTo = options.chainLogTo;
|
|
163
|
-
if (typeof options.pipeLogTo === 'function')
|
|
164
|
-
LOG_OPTIONS.pipeTo = options.pipeLogTo;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (setLang) {
|
|
168
|
-
const lngRequested = options.lang;
|
|
169
|
-
const lng = checkPreferredLanguage(_GlobalData_js__WEBPACK_IMPORTED_MODULE_3__["default"].languages, 'en', lngRequested);
|
|
170
|
-
log('debug', `Language ${lngRequested ? `requested: "${lngRequested}" ` : ''} used: "${lng}"`);
|
|
171
|
-
_messages = lng === 'en' ? {} : _GlobalData_js__WEBPACK_IMPORTED_MODULE_3__["default"].messages[lng];
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return options;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Function that will return the translation of the provided key
|
|
179
|
-
* into the current language.
|
|
180
|
-
* @param {string} key - ID of the expression to be translated
|
|
181
|
-
* @returns {string} - The translated text
|
|
182
|
-
*/
|
|
183
|
-
function getMsg(key) {
|
|
184
|
-
return _messages[key] || key;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Converts expressions of type 'pt-br', 'FR', 'ca_es@valencia'... to the format expected by the i18n system:
|
|
189
|
-
* lc[_CC][@variant] where 'lc' is a two or three lowercase letter language code, CC is an optional two uppercase
|
|
190
|
-
* letter country code, followed by an optional 'variant' consisting in letters and/or digits.
|
|
191
|
-
* @param {string} locale - The locale expression to be normalized
|
|
192
|
-
* @returns string - The normalized locale
|
|
193
|
-
*/
|
|
194
|
-
function normalizeLocale(locale = '') {
|
|
195
|
-
const [, language = null, country = null, variant = null] = /^([a-zA-Z]{2,3})[_-]?([a-zA-Z]{2})?@?([a-zA-Z0-9]*)?$/.exec(locale.trim()) || [];
|
|
196
|
-
return language
|
|
197
|
-
? `${language.toLowerCase()}${country ? `_${country.toUpperCase()}` : ''}${variant ? `@${variant.toLowerCase()}` : ''}`
|
|
198
|
-
: '';
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Checks if the language preferred by the user (based on browser and/or specific settings)
|
|
203
|
-
* is in a list of available languages.
|
|
204
|
-
* @param {string[]} availableLangs - Array of available languages. It should contain at least one item.
|
|
205
|
-
* @param {string} [defaultLang=en] - Language to be used by default when not found the selected one
|
|
206
|
-
* @param {string} [requestedLang=''] - Request this specific language
|
|
207
|
-
* @returns {string} - The most suitable language for this request
|
|
208
|
-
*/
|
|
209
|
-
function checkPreferredLanguage(availableLangs, defaultLang = 'en', requestedLang = '') {
|
|
210
|
-
let result = -1;
|
|
211
|
-
|
|
212
|
-
// Create an array to store possible values
|
|
213
|
-
let tries = [];
|
|
214
|
-
|
|
215
|
-
// If "setLang" is specified, check it
|
|
216
|
-
if (requestedLang) {
|
|
217
|
-
// Normalize requested locale
|
|
218
|
-
const lang = normalizeLocale(requestedLang);
|
|
219
|
-
if (lang)
|
|
220
|
-
tries.push(lang);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Add user's preferred languages, if any
|
|
224
|
-
if (window.navigator.languages)
|
|
225
|
-
tries = tries.concat(window.navigator.languages);
|
|
226
|
-
|
|
227
|
-
// Add the navigator main language, if defined
|
|
228
|
-
if (window.navigator.language)
|
|
229
|
-
tries.push(window.navigator.language);
|
|
230
|
-
|
|
231
|
-
// Add English as final option
|
|
232
|
-
tries.push(defaultLang);
|
|
233
|
-
|
|
234
|
-
for (let i = 0; i < tries.length; i++) {
|
|
235
|
-
let match = -1;
|
|
236
|
-
for (let n in availableLangs) {
|
|
237
|
-
if (tries[i].indexOf(availableLangs[n]) === 0) {
|
|
238
|
-
match = n;
|
|
239
|
-
if (tries[i] === availableLangs[n]) {
|
|
240
|
-
result = n;
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
if (result >= 0 || (result = match) >= 0)
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
return availableLangs[result >= 0 ? result : 0];
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Establishes the current verbosity level of the logging system
|
|
253
|
-
* @param {string} level - One of the valid strings in {@link module:Utils.LOG_LEVELS}
|
|
254
|
-
*/
|
|
255
|
-
function setLogLevel(level) {
|
|
256
|
-
const log = LOG_LEVELS.indexOf(level);
|
|
257
|
-
if (log >= 0)
|
|
258
|
-
LOG_OPTIONS.level = log;
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Reports a new message to the logging system
|
|
263
|
-
* @param {string} type - The type of message. Mus be `error`, `warn`, `info`, `debug` or `trace`.
|
|
264
|
-
* @param {string} msg - The main message to be logged. Additional parameters can be added, like
|
|
265
|
-
* in `console.log` (see: {@link https://developer.mozilla.org/en-US/docs/Web/API/Console/log})
|
|
266
|
-
*/
|
|
267
|
-
function log(type, msg) {
|
|
268
|
-
const level = LOG_LEVELS.indexOf(type);
|
|
269
|
-
const args = Array.prototype.slice.call(arguments);
|
|
270
|
-
|
|
271
|
-
// Check if message should currently be logged
|
|
272
|
-
if (level < 0 || level <= LOG_OPTIONS.level) {
|
|
273
|
-
if (LOG_OPTIONS.pipeTo)
|
|
274
|
-
LOG_OPTIONS.pipeTo.apply(null, args);
|
|
275
|
-
else {
|
|
276
|
-
const mainMsg = `${LOG_OPTIONS.prefix || ''} ${LOG_PRINT_LABELS[level]} ${LOG_OPTIONS.timestamp ? getDateTime() : ''} ${msg}`;
|
|
277
|
-
console[level === 1 ? 'error' : level === 2 ? 'warn' : 'log'].apply(console, [mainMsg].concat(args.slice(2)));
|
|
278
|
-
// Call chained logger, if anny
|
|
279
|
-
if (LOG_OPTIONS.chainTo)
|
|
280
|
-
LOG_OPTIONS.chainTo.apply(null, args);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Gets a boolean value from a textual expression
|
|
287
|
-
* @param {string} val - The value to be parsed (`true` for true, null or otherwise for `false`)
|
|
288
|
-
* @param {boolean} [defaultValue=false] - The default value to return when `val` is false
|
|
289
|
-
* @returns {number}
|
|
290
|
-
*/
|
|
291
|
-
function getBoolean(val, defaultValue = false) {
|
|
292
|
-
return val === 'true' ? true : val === 'false' ? false : defaultValue;
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Gets a value from an given expression that can be `null`, `undefined` or empty string ('')
|
|
297
|
-
* @param {any} val - The expression to parse
|
|
298
|
-
* @param {any} [defaultValue=null] - The value to return when `val` is `null`, `''` or `undefined`
|
|
299
|
-
* @returns {any}
|
|
300
|
-
*/
|
|
301
|
-
function getVal(val, defaultValue = null) {
|
|
302
|
-
return (val === '' || val === null || typeof val === 'undefined') ? defaultValue : val;
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Gets a number from a string or another number
|
|
307
|
-
* @param {any} val - The expression to parse
|
|
308
|
-
* @param {number} [defaultValue=0] - The default value
|
|
309
|
-
* @returns {number}
|
|
310
|
-
*/
|
|
311
|
-
function getNumber(val, defaultValue) {
|
|
312
|
-
return Number(getVal(val, defaultValue));
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Gets the plain percent expression (without decimals) of the given value
|
|
317
|
-
* @param {number} val - The value to be expressed as a percentile
|
|
318
|
-
* @returns {string}
|
|
319
|
-
*/
|
|
320
|
-
function getPercent(val) {
|
|
321
|
-
return `${Math.round(val * 100)}%`;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Returns the two-digits text expression representing the given number (lesser than 100) zero-padded at left
|
|
326
|
-
* Useful for representing hours, minutes and seconds
|
|
327
|
-
* @param {number} val - The number to be processed
|
|
328
|
-
* @returns {string}
|
|
329
|
-
*/
|
|
330
|
-
function zp(val) {
|
|
331
|
-
return `0${val}`.slice(-2);
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Returns a given time in [00h 00'00"] format
|
|
336
|
-
* @param {number} millis - Amount of milliseconds to be processed
|
|
337
|
-
* @returns {string}
|
|
338
|
-
*/
|
|
339
|
-
function getHMStime(millis) {
|
|
340
|
-
const d = new Date(millis);
|
|
341
|
-
const h = d.getUTCHours(), m = d.getUTCMinutes(), s = d.getUTCSeconds();
|
|
342
|
-
return `${h ? h + 'h ' : ''}${h || m ? zp(m) + '\'' : ''}${zp(s)}"`;
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Returns a formatted string with the provided date and time
|
|
347
|
-
* @param {external:Date} date - The date to be formatted. When `null` or `undefined`, the current date will be used.
|
|
348
|
-
* @returns {string}
|
|
349
|
-
*/
|
|
350
|
-
function getDateTime(date = new Date()) {
|
|
351
|
-
return `${date.getFullYear()}/${zp(date.getMonth() + 1)}/${zp(date.getDate())} ${zp(date.getHours())}:${zp(date.getMinutes())}:${zp(date.getSeconds())}`;
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Parse 'date' fields generated by "JClic Author" in format d/m/y, with
|
|
356
|
-
* variable number of digits.
|
|
357
|
-
* @param {string} text - The old 'date' field
|
|
358
|
-
* @returns {external:Date} - Always return a Date object (now, if text was invalid)
|
|
359
|
-
*/
|
|
360
|
-
function parseOldDate(text) {
|
|
361
|
-
let result = null;
|
|
362
|
-
if (text) {
|
|
363
|
-
const elements = text.trim().split('/');
|
|
364
|
-
if (elements.length === 3) {
|
|
365
|
-
let m = parseInt(elements[0]) || 0;
|
|
366
|
-
let d = parseInt(elements[1]) || 0;
|
|
367
|
-
let y = parseInt(elements[2]) || 0;
|
|
368
|
-
if (m > 12 && d <= 12) {
|
|
369
|
-
const t = m;
|
|
370
|
-
m = d;
|
|
371
|
-
d = t;
|
|
372
|
-
}
|
|
373
|
-
if (y < 1980)
|
|
374
|
-
y += (y < 90 ? 2000 : 1900);
|
|
375
|
-
if (d && m && y) {
|
|
376
|
-
result = new Date(Date.parse(`${m}/${d}/${y}`));
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
return result || new Date();
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Extracts just the ISO-639 language code from complex
|
|
385
|
-
* expressions like "English (en)", buid by JClic Author.
|
|
386
|
-
* @param {string} text - The expression to parse
|
|
387
|
-
* @returns {string} - The ISO-639 language code, or '--' if none found
|
|
388
|
-
*/
|
|
389
|
-
function cleanOldLanguageTag(text) {
|
|
390
|
-
if (!text)
|
|
391
|
-
text = '--';
|
|
392
|
-
// Allow only ISO-639-1 and ISO-639-2 language codes
|
|
393
|
-
else if (!text.match(/^[a-z][a-z][a-z]?$/)) {
|
|
394
|
-
const matches = text.match(/\(([a-z][a-z][a-z]?)\)/);
|
|
395
|
-
if (matches && matches.length === 2)
|
|
396
|
-
text = matches[1];
|
|
397
|
-
else
|
|
398
|
-
text = '--';
|
|
399
|
-
}
|
|
400
|
-
return text;
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
/** @const {number} */
|
|
404
|
-
const FALSE = 0;
|
|
405
|
-
|
|
406
|
-
/** @const {number} */
|
|
407
|
-
const TRUE = 1;
|
|
408
|
-
|
|
409
|
-
/** @const {number} */
|
|
410
|
-
const DEFAULT = 2;
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Gets a numeric value (0, 1 or 2) from a set of possible values: `false`, `true` and `default`.
|
|
414
|
-
* @param {string} val - The text to be parsed
|
|
415
|
-
* @param {any} def - An optional default value
|
|
416
|
-
* @returns {number}
|
|
417
|
-
*/
|
|
418
|
-
function getTriState(val, def = DEFAULT) {
|
|
419
|
-
return val === 'true' ? TRUE : val === 'false' ? FALSE : def;
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
* Returns a string with the given `tag` repeated n times
|
|
424
|
-
* @param {string} tag - The tag to be repeated
|
|
425
|
-
* @param {number} repeats - The number of times to repeat the tag
|
|
426
|
-
* @returns {string}
|
|
427
|
-
*/
|
|
428
|
-
function fillString(tag, repeats = 0) {
|
|
429
|
-
return Array(repeats).fill(tag).join('');
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Checks if the provided value is 'null' or 'undefined'.
|
|
434
|
-
* @param {any} val - The value to be parsed
|
|
435
|
-
* @returns {boolean}
|
|
436
|
-
*/
|
|
437
|
-
function isNullOrUndef(val) {
|
|
438
|
-
return typeof val === 'undefined' || val === null;
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Checks if two expressions are equivalent.
|
|
443
|
-
* Returns `true` when both parameters are `null` or `undefined`, and also when both have
|
|
444
|
-
* equivalent values.
|
|
445
|
-
* @param {any} a
|
|
446
|
-
* @param {any} b
|
|
447
|
-
* @returns {boolean}
|
|
448
|
-
*/
|
|
449
|
-
function isEquivalent(a, b) {
|
|
450
|
-
return (typeof a === 'undefined' || a === null) && (typeof b === 'undefined' || b === null) || a === b;
|
|
451
|
-
};
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Reads paragraphs, identified by `<p></p>` elements, inside XML data
|
|
455
|
-
* @param {object} xml - The DOM-XML element to be parsed
|
|
456
|
-
* @returns {string}
|
|
457
|
-
*/
|
|
458
|
-
function getXmlText(xml) {
|
|
459
|
-
let text = '';
|
|
460
|
-
jquery__WEBPACK_IMPORTED_MODULE_0___default()(xml).children('p').each((_n, child) => { text += `<p>${child.textContent}</p>`; });
|
|
461
|
-
return text;
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Parse the provided XML element node, returning a complex object
|
|
466
|
-
* @param {object} xml - The root XML element to parse
|
|
467
|
-
* @param {boolean} [withText=false] - When `true`, any text found inside the XML element is also included in the resulting object.
|
|
468
|
-
* @returns {object}
|
|
469
|
-
*/
|
|
470
|
-
function parseXmlNode(xml, withText = false) {
|
|
471
|
-
// Initialize the resulting object
|
|
472
|
-
const result = {};
|
|
473
|
-
// Direct copy of root element attributes as object properties
|
|
474
|
-
if (xml.attributes)
|
|
475
|
-
attrForEach(xml.attributes, (name, value) => result[name] = /^-?\d*$/.test(value) ? Number(value) : value);
|
|
476
|
-
|
|
477
|
-
const keys = [];
|
|
478
|
-
const children = Array.from(xml.children || xml.childNodes || []);
|
|
479
|
-
|
|
480
|
-
// If all children is of type 'p', just compile it in a single string
|
|
481
|
-
const paragraphs = children.filter(child => child.nodeName === 'p');
|
|
482
|
-
if (paragraphs.length > 0 && paragraphs.length === children.filter(ch => ch.nodeName !== '#text').length) {
|
|
483
|
-
const text = paragraphs.map(ch => ch.textContent).join('\n');
|
|
484
|
-
if (xml.attributes) {
|
|
485
|
-
result.text = text;
|
|
486
|
-
return result;
|
|
487
|
-
}
|
|
488
|
-
return text;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// Process children elements
|
|
492
|
-
children.forEach(child => {
|
|
493
|
-
// Avoid extra text content collected by [xmldom](https://www.npmjs.com/package/xmldom)
|
|
494
|
-
if (child.nodeName === '#text' && !withText)
|
|
495
|
-
return;
|
|
496
|
-
|
|
497
|
-
// Recursive processing of children
|
|
498
|
-
const ch = parseXmlNode(child, withText);
|
|
499
|
-
// Store the result into a temporary object named as the child node name,
|
|
500
|
-
if (!result[child.nodeName]) {
|
|
501
|
-
// Create object and save key for later processing
|
|
502
|
-
result[child.nodeName] = {};
|
|
503
|
-
keys.push(child.nodeName);
|
|
504
|
-
}
|
|
505
|
-
// Use 'id' (or an incremental number if 'id' is not set) as a key
|
|
506
|
-
if (ch.id)
|
|
507
|
-
result[child.nodeName][ch.id] = ch;
|
|
508
|
-
else {
|
|
509
|
-
const n = Object.keys(result[child.nodeName]).length;
|
|
510
|
-
result[child.nodeName][n] = ch;
|
|
511
|
-
}
|
|
512
|
-
});
|
|
513
|
-
// Check temporary objects, converting it to an array, a single object or a complex object
|
|
514
|
-
keys.forEach(k => {
|
|
515
|
-
// Retrieve temporary object from `keys`
|
|
516
|
-
const kx = Object.keys(result[k]);
|
|
517
|
-
// If all keys are numbers, convert object into an array (or leave it as a single object)
|
|
518
|
-
if (!kx.find(kk => isNaN(kk))) {
|
|
519
|
-
if (kx.length === 1)
|
|
520
|
-
// Array with a single element. Leave it as a simple object:
|
|
521
|
-
result[k] = result[k][0];
|
|
522
|
-
else {
|
|
523
|
-
// Object with numeric keys. Convert it to array:
|
|
524
|
-
const arr = [];
|
|
525
|
-
kx.forEach(kk => arr.push(result[k][kk]));
|
|
526
|
-
result[k] = arr;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
});
|
|
530
|
-
// Save text content, if any:
|
|
531
|
-
if (children.length === 0 && xml.textContent)
|
|
532
|
-
result.textContent = xml.textContent;
|
|
533
|
-
return result;
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
/**
|
|
537
|
-
* Parse the given XML node, known as containing only text elements,
|
|
538
|
-
* and return its content as a string (when possible)
|
|
539
|
-
* @param {object} xml - The XML element to parse
|
|
540
|
-
* @returns {string|object}
|
|
541
|
-
*/
|
|
542
|
-
function getXmlNodeText(node) {
|
|
543
|
-
const result = parseXmlNode(node);
|
|
544
|
-
return typeof result === 'string' ?
|
|
545
|
-
result :
|
|
546
|
-
result.hasOwnProperty('text') ?
|
|
547
|
-
result.text :
|
|
548
|
-
result.hasOwnProperty('textContent') ?
|
|
549
|
-
result.textContent :
|
|
550
|
-
result;
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Recursively explore the given object, converting to a string
|
|
555
|
-
* all attributes with a single attribute named 'text'.
|
|
556
|
-
* Example:
|
|
557
|
-
* {a:1, b:{text:"hello"}, c:{d:2, text:"world"}} => {a:1, b:"hello", c:{d:2, text:"world"}}
|
|
558
|
-
* @param {object} obj - The object to explore
|
|
559
|
-
* @returns {object} - The same object, with text attributes reduced to strings
|
|
560
|
-
*/
|
|
561
|
-
function reduceTextsToStrings(obj) {
|
|
562
|
-
if (obj) {
|
|
563
|
-
const keys = Object.keys(obj);
|
|
564
|
-
keys.forEach(k => {
|
|
565
|
-
const attr = obj[k];
|
|
566
|
-
if (typeof attr === 'object') {
|
|
567
|
-
const ko = Object.keys(attr);
|
|
568
|
-
if (ko.length === 1 && ko[0] === 'text')
|
|
569
|
-
obj[k] = attr.text;
|
|
570
|
-
else
|
|
571
|
-
obj[k] = reduceTextsToStrings(attr);
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
return obj;
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
/**
|
|
579
|
-
* Creates a string suitable to be used in the 'style' attribute of HTML tags, filled with the
|
|
580
|
-
* CSS attributes contained in the provided object.
|
|
581
|
-
* @param {object} cssObj
|
|
582
|
-
* @returns {string}
|
|
583
|
-
*/
|
|
584
|
-
function cssToString(cssObj) {
|
|
585
|
-
return Object.keys(cssObj).reduce((s, key) => `${s}${key}:${cssObj[key]};`, '');
|
|
586
|
-
};
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* Converts java-like color codes (like '0xRRGGBB') to valid CSS values like '#RRGGBB' or 'rgba(r,g,b,a)'
|
|
590
|
-
* @param {string} [color] - A color, as codified in Java
|
|
591
|
-
* @param {string} [defaultColor] - The default color to be used
|
|
592
|
-
* @returns {string}
|
|
593
|
-
*/
|
|
594
|
-
function checkColor(color, defaultColor = settings.BoxBase.BACK_COLOR) {
|
|
595
|
-
if (typeof color === 'undefined' || color === null)
|
|
596
|
-
color = defaultColor;
|
|
597
|
-
color = color.replace('0x', '#');
|
|
598
|
-
// Check for Alpha value
|
|
599
|
-
if (color.charAt(0) === '#' && color.length > 7) {
|
|
600
|
-
const alpha = fx(parseInt(color.substring(1, 3), 16) / 255.0, 2);
|
|
601
|
-
color = `rgba(${parseInt(color.substring(3, 5), 16)},${parseInt(color.substring(5, 7), 16)},${parseInt(color.substring(7, 9), 16)},${alpha})`;
|
|
602
|
-
}
|
|
603
|
-
return color;
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
/**
|
|
607
|
-
* Checks if the provided color has an alpha value less than 1
|
|
608
|
-
* @param {string} color - The color to be analyzed
|
|
609
|
-
* @returns {boolean}
|
|
610
|
-
*/
|
|
611
|
-
function colorHasTransparency(color) {
|
|
612
|
-
if (startsWith(color, 'rgba(')) {
|
|
613
|
-
var alpha = parseInt(color.substring(color.lastIndexOf(',')));
|
|
614
|
-
return typeof alpha === 'number' && alpha < 1.0;
|
|
615
|
-
}
|
|
616
|
-
return false;
|
|
617
|
-
};
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Clones the provided object
|
|
621
|
-
* See: https://stackoverflow.com/questions/41474986/how-to-clone-a-javascript-es6-class-instance
|
|
622
|
-
* @param {object} obj
|
|
623
|
-
* @returns {object}
|
|
624
|
-
*/
|
|
625
|
-
//cloneObject: obj => Object.assign(Object.create(Object.getPrototypeOf(obj)), obj),
|
|
626
|
-
function cloneObject(obj) {
|
|
627
|
-
return jquery__WEBPACK_IMPORTED_MODULE_0___default().extend(true, Object.create(Object.getPrototypeOf(obj)), obj);
|
|
628
|
-
};
|
|
629
|
-
|
|
630
|
-
/**
|
|
631
|
-
* Converts string values to number or boolean when needed
|
|
632
|
-
* @param {object} obj - The object to be processed
|
|
633
|
-
* @returns {object} - A new object with normalized content
|
|
634
|
-
*/
|
|
635
|
-
function normalizeObject(obj) {
|
|
636
|
-
const result = {};
|
|
637
|
-
if (obj)
|
|
638
|
-
jquery__WEBPACK_IMPORTED_MODULE_0___default().each(obj, (key, value) => {
|
|
639
|
-
let s;
|
|
640
|
-
if (typeof value === 'string' && (s = value.trim().toLowerCase()) !== '')
|
|
641
|
-
value = s === 'true' ? true : s === 'false' ? false : isNaN(s) ? value : Number(s);
|
|
642
|
-
result[key] = value;
|
|
643
|
-
});
|
|
644
|
-
return result;
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
/**
|
|
648
|
-
* Returns an partial clone of an object, containing only the own attributes specified in an array of possible keys.
|
|
649
|
-
* When the value of an attribute is of type 'Object' and this object has a method named `getAttributes`, the result of calling
|
|
650
|
-
* this method is returned instead of the crude object.
|
|
651
|
-
* @param {object} obj - The object to be processed
|
|
652
|
-
* @param {string[]} [keys] - An optional array of keys to be included in the resulting object.
|
|
653
|
-
* When null or not set, all keys of `obj` are included. Keys can include a default value separed by '|'.
|
|
654
|
-
* Attributes with default value will be excluded from the resulting object.
|
|
655
|
-
* @returns {object}
|
|
656
|
-
*/
|
|
657
|
-
function getAttr(obj, keys = null) {
|
|
658
|
-
let result = {};
|
|
659
|
-
keys = keys || Object.keys(obj);
|
|
660
|
-
keys.forEach(key => {
|
|
661
|
-
const [k, d] = key.split('|');
|
|
662
|
-
if (obj.hasOwnProperty(k) && typeof obj[k] !== 'undefined' && obj[k] !== null && obj[k].toString() !== d) {
|
|
663
|
-
const v = getValue(obj[k]);
|
|
664
|
-
if (!isEmpty(v))
|
|
665
|
-
result[k] = v;
|
|
666
|
-
}
|
|
667
|
-
});
|
|
668
|
-
|
|
669
|
-
// Convert to string objects with only a "text" attribute
|
|
670
|
-
keys = Object.keys(result);
|
|
671
|
-
if (keys.length === 1 && keys[0] === 'text')
|
|
672
|
-
result = result.text;
|
|
673
|
-
|
|
674
|
-
return result;
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* Gets the minimal representation of the given value (object, array, string, number...)
|
|
679
|
-
* @param {any} value - The value to be processed
|
|
680
|
-
* @returns {any}
|
|
681
|
-
*/
|
|
682
|
-
function getValue(value) {
|
|
683
|
-
return value.getAttributes ?
|
|
684
|
-
value.getAttributes() :
|
|
685
|
-
value instanceof Array ?
|
|
686
|
-
value.map(e => getValue(e)) :
|
|
687
|
-
value instanceof Date ?
|
|
688
|
-
value.toISOString() :
|
|
689
|
-
value instanceof Object ?
|
|
690
|
-
getAttr(value) :
|
|
691
|
-
value;
|
|
692
|
-
};
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* Checks if the given value is an empty object, null or a zero-length string
|
|
696
|
-
* @param {any} v - The value to be checked
|
|
697
|
-
* @returns {boolean} - `true` if `v` is `{}`, `null` or `""`
|
|
698
|
-
*/
|
|
699
|
-
function isEmpty(v) {
|
|
700
|
-
let result = (typeof v === 'undefined' || v === null);
|
|
701
|
-
if (!result) {
|
|
702
|
-
switch (typeof v) {
|
|
703
|
-
case 'object':
|
|
704
|
-
result = Object.keys(v).length === 0;
|
|
705
|
-
break;
|
|
706
|
-
|
|
707
|
-
case 'string':
|
|
708
|
-
result = v.length === 0;
|
|
709
|
-
break;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
return result;
|
|
713
|
-
};
|
|
714
|
-
|
|
715
|
-
/**
|
|
716
|
-
* Fills an object with specific attributes from another data object
|
|
717
|
-
* @param {object} obj - The target object
|
|
718
|
-
* @param {object} data - The data object
|
|
719
|
-
* @param {string[]} attr - The list of attributes to be copied from `data` to `obj`
|
|
720
|
-
* Elements of this list can be:
|
|
721
|
-
* a) Just a string. In this case, the native object will be used as a value
|
|
722
|
-
* b) An object with the following members:
|
|
723
|
-
* - `key`{string} - The attribute name
|
|
724
|
-
* - `fn` {function} - The function to be invoked to build the object
|
|
725
|
-
* - `params` {string[]} - Optional params to be passed to the `setAttributes` method of the created object
|
|
726
|
-
* - `group` {string} - Used when `data` is an object or an array (possible values are `object` and `array`), and multiple results
|
|
727
|
-
* should be aggregated in a resulting object or array with the same keys (or ordering) as data.
|
|
728
|
-
* - `init` {string} - Optional parameter indicating if `fn` should be passed with an additional param. This param can be:
|
|
729
|
-
* - `key` - The member's key
|
|
730
|
-
*
|
|
731
|
-
* @returns {object} - Always returns `obj`
|
|
732
|
-
*/
|
|
733
|
-
function setAttr(obj, data, attr) {
|
|
734
|
-
attr.forEach(a => {
|
|
735
|
-
if (a.key) {
|
|
736
|
-
const { key, fn, group, init, params } = a;
|
|
737
|
-
// A new object should be built
|
|
738
|
-
if (!isEmpty(data[key])) {
|
|
739
|
-
const dataset = data[key];
|
|
740
|
-
if (group === 'object')
|
|
741
|
-
obj[key] = Object.keys(dataset).reduce((o, k) => {
|
|
742
|
-
o[k] = buildObj(fn, dataset[k], init === 'key' ? k : init, params);
|
|
743
|
-
return o;
|
|
744
|
-
}, {});
|
|
745
|
-
else if (group === 'array')
|
|
746
|
-
obj[key] = dataset.map((element, n) => buildObj(fn, element, init === 'key' ? n : init, params));
|
|
747
|
-
else
|
|
748
|
-
obj[key] = buildObj(fn, dataset, init, params);
|
|
749
|
-
}
|
|
750
|
-
} else if (!isEmpty(data[a]))
|
|
751
|
-
obj[a] = data[a];
|
|
752
|
-
});
|
|
753
|
-
return obj;
|
|
754
|
-
};
|
|
755
|
-
|
|
756
|
-
/**
|
|
757
|
-
* Builds a new object based on the provided constructor, data and initialization value
|
|
758
|
-
* Objects used with this function should implement `setAttributes`, or an static method named `factory`
|
|
759
|
-
* @param {function} objType - A class or function to be invoked to build the object.
|
|
760
|
-
* @param {object} [data] - An optional object filled with the attributes to be assigned to the newly created object.
|
|
761
|
-
* @param {any} [init] - An optional value to be passed to the function when invoked with `new`
|
|
762
|
-
* @param {object[]} [params=[]] - Optional array of params to be passed when calling `setAttributes` on the final object
|
|
763
|
-
* @returns {object} - The resulting object
|
|
764
|
-
*/
|
|
765
|
-
function buildObj(objType, data, init, params = []) {
|
|
766
|
-
return objType.factory ? objType.factory(data, init, params) : new objType(init).setAttributes(data, ...params);
|
|
767
|
-
};
|
|
768
|
-
|
|
769
|
-
/**
|
|
770
|
-
* Check if the given char is a separator
|
|
771
|
-
* @param {string} ch - A string with a single character
|
|
772
|
-
* @returns {boolean}
|
|
773
|
-
*/
|
|
774
|
-
function isSeparator(ch) {
|
|
775
|
-
return settings.SEPARATORS.includes(ch);
|
|
776
|
-
};
|
|
777
|
-
|
|
778
|
-
/**
|
|
779
|
-
* Check if the given char is a word delimiter
|
|
780
|
-
* @param {string} ch - A string with a single character
|
|
781
|
-
* @returns {boolean}
|
|
782
|
-
*/
|
|
783
|
-
function isWordDelimiter(ch) {
|
|
784
|
-
return settings.WORD_DELIMITERS.includes(ch);
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
/**
|
|
788
|
-
* Converts a string in an array of objects with 'text' and 'sep' attributes, where 'text' are single words and 'sep'
|
|
789
|
-
* are the word separators following each word in the sentence.
|
|
790
|
-
* @example
|
|
791
|
-
* stringToWords("Hello, World! That's all") returns:
|
|
792
|
-
* [
|
|
793
|
-
* {text: "Hello", sep: ", "},
|
|
794
|
-
* {text: "World", sep: "! "},
|
|
795
|
-
* {text: "That", sep: "'"},
|
|
796
|
-
* {text: "s", sep: " "},
|
|
797
|
-
* {text: "all", sep: ""},
|
|
798
|
-
* ]
|
|
799
|
-
* @param {*} str - The text to be tokenized
|
|
800
|
-
* @returns {object[]}
|
|
801
|
-
*/
|
|
802
|
-
function stringToWords(str) {
|
|
803
|
-
const result = [];
|
|
804
|
-
let token = { text: '', sep: '' };
|
|
805
|
-
let inWord = true;
|
|
806
|
-
for (let i = 0; i < str.length; i++) {
|
|
807
|
-
const ch = str.charAt(i);
|
|
808
|
-
const delim = isWordDelimiter(ch);
|
|
809
|
-
if (inWord) {
|
|
810
|
-
if (!delim)
|
|
811
|
-
token.text += ch;
|
|
812
|
-
else {
|
|
813
|
-
inWord = false;
|
|
814
|
-
token.sep = ch;
|
|
815
|
-
}
|
|
816
|
-
} else {
|
|
817
|
-
if (delim)
|
|
818
|
-
token.sep += ch;
|
|
819
|
-
else {
|
|
820
|
-
result.push(token);
|
|
821
|
-
token = { text: ch, sep: '' };
|
|
822
|
-
inWord = true;
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
result.push(token);
|
|
827
|
-
return result;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
/**
|
|
831
|
-
* Rounds `v` to the nearest multiple of `n`
|
|
832
|
-
* @param {number} v
|
|
833
|
-
* @param {number} n - Cannot be zero!
|
|
834
|
-
* @returns {number}
|
|
835
|
-
*/
|
|
836
|
-
function roundTo(v, n) {
|
|
837
|
-
return Math.round(v / n) * n;
|
|
838
|
-
};
|
|
839
|
-
|
|
840
|
-
/**
|
|
841
|
-
* Set the maximum number of decimals for a number
|
|
842
|
-
* @param {any} v - The value to be converted to a fixed number of decimals. Can be anything.
|
|
843
|
-
* @param {number} n=4 - the maximum number of decimals
|
|
844
|
-
* @returns {any} - When `v` is a number, a number with fixed decimals is returned. Otherwise, returns `v`
|
|
845
|
-
*/
|
|
846
|
-
function fx(v, n = 4) {
|
|
847
|
-
return v.toFixed ? Number(v.toFixed(n)) : v;
|
|
848
|
-
};
|
|
849
|
-
|
|
850
|
-
/**
|
|
851
|
-
* Compares the provided answer against multiple valid options. These valid options are
|
|
852
|
-
* concatenated in a string, separated by pipe chars (`|`). The comparing can be case sensitive.
|
|
853
|
-
* @param {string} answer - The text to check against to
|
|
854
|
-
* @param {string} check - String containing one or multiple options, separated by `|`
|
|
855
|
-
* @param {boolean} [checkCase=false] - When true, the comparing will be case-sensitive
|
|
856
|
-
* @param {boolean} [numeric=false] - When true, we are comparing numeric expressions
|
|
857
|
-
* @returns {boolean}
|
|
858
|
-
*/
|
|
859
|
-
function compareMultipleOptions(answer, check, checkCase = false, numeric = false) {
|
|
860
|
-
if (answer === null || answer.length === 0 || check === null || check.length === 0)
|
|
861
|
-
return false;
|
|
862
|
-
if (!checkCase && !numeric)
|
|
863
|
-
answer = answer.toUpperCase();
|
|
864
|
-
answer = answer.trim();
|
|
865
|
-
|
|
866
|
-
// Check for numeric digits in answer!
|
|
867
|
-
numeric = numeric && /\d/.test(answer);
|
|
868
|
-
|
|
869
|
-
for (let token of check.split('|')) {
|
|
870
|
-
if (numeric) {
|
|
871
|
-
if (Number.parseFloat(answer.replace(/,/, '.')) === Number.parseFloat(token.replace(/,/, '.')))
|
|
872
|
-
return true;
|
|
873
|
-
}
|
|
874
|
-
else if (answer === (checkCase ? token : token.toUpperCase()).trim())
|
|
875
|
-
return true;
|
|
876
|
-
}
|
|
877
|
-
return false;
|
|
878
|
-
};
|
|
879
|
-
|
|
880
|
-
/**
|
|
881
|
-
* Checks if the given string ends with the specified expression
|
|
882
|
-
* @param {string} text - The string where to find the expression
|
|
883
|
-
* @param {string} expr - The expression to search for.
|
|
884
|
-
* @param {boolean} [trim] - When `true`, the `text` string will be trimmed before check
|
|
885
|
-
* @returns {boolean}
|
|
886
|
-
*/
|
|
887
|
-
function endsWith(text = '', expr, trim) {
|
|
888
|
-
return typeof text === 'string' && (trim ? text.trim() : text).endsWith(expr);
|
|
889
|
-
};
|
|
890
|
-
|
|
891
|
-
/**
|
|
892
|
-
* Checks if the given string starts with the specified expression
|
|
893
|
-
* @param {string} text - The string where to find the expression
|
|
894
|
-
* @param {string} expr - The expression to search for.
|
|
895
|
-
* @param {boolean} [trim] - When `true`, the `text` string will be trimmed before check
|
|
896
|
-
* @returns {boolean}
|
|
897
|
-
*/
|
|
898
|
-
function startsWith(text = '', expr, trim) {
|
|
899
|
-
return typeof text === 'string' && (trim ? text.trim() : text).indexOf(expr) === 0;
|
|
900
|
-
};
|
|
901
|
-
|
|
902
|
-
/**
|
|
903
|
-
* Replaces all occurrences of the backslash character (`\`) by a regular slash (`/`)
|
|
904
|
-
* This is useful to normalize bad path names present in some old JClic projects
|
|
905
|
-
* @param {string} str - The string to be normalized
|
|
906
|
-
* @returns {string}
|
|
907
|
-
*/
|
|
908
|
-
function nSlash(str) {
|
|
909
|
-
return str ? str.replace(/\\/g, '/') : str;
|
|
910
|
-
};
|
|
911
|
-
|
|
912
|
-
/**
|
|
913
|
-
* Checks if the given expression is an absolute URL
|
|
914
|
-
* @param {string} exp - The expression to be checked
|
|
915
|
-
* @returns {boolean}
|
|
916
|
-
*/
|
|
917
|
-
function isURL(exp) {
|
|
918
|
-
return /^(filesystem:)?(https?|file|data|ftps?):/i.test(exp);
|
|
919
|
-
};
|
|
920
|
-
|
|
921
|
-
/**
|
|
922
|
-
* Gets the base path of the given file path (absolute or full URL). This base path always ends
|
|
923
|
-
* with `/`, meaning it can be concatenated with relative paths without adding a separator.
|
|
924
|
-
* @param {string} path - The full path to be parsed
|
|
925
|
-
* @returns {string}
|
|
926
|
-
*/
|
|
927
|
-
function getBasePath(path) {
|
|
928
|
-
const p = path.lastIndexOf('/');
|
|
929
|
-
return p >= 0 ? path.substring(0, p + 1) : '';
|
|
930
|
-
};
|
|
931
|
-
|
|
932
|
-
/**
|
|
933
|
-
* Gets the full path of `file` relative to `basePath`
|
|
934
|
-
* @param {string} file - The file name
|
|
935
|
-
* @param {string} [path] - The base path
|
|
936
|
-
* @returns {string}
|
|
937
|
-
*/
|
|
938
|
-
function getRelativePath(file, path) {
|
|
939
|
-
return (!path || path === '' || file.indexOf(path) !== 0) ? file : file.substring(path.length);
|
|
940
|
-
};
|
|
941
|
-
|
|
942
|
-
/**
|
|
943
|
-
* Gets the complete path of a relative or absolute URL, using the provided `basePath`
|
|
944
|
-
* @param {string} basePath - The base URL
|
|
945
|
-
* @param {string} path - The filename
|
|
946
|
-
* @returns {string}
|
|
947
|
-
*/
|
|
948
|
-
function getPath(basePath, path) {
|
|
949
|
-
return isURL(path) ? path : basePath + path;
|
|
950
|
-
};
|
|
951
|
-
|
|
952
|
-
/**
|
|
953
|
-
* Gets a promise with the complete path of a relative or absolute URL, using the provided `basePath`
|
|
954
|
-
* @param {string} basePath - The base URL
|
|
955
|
-
* @param {string} path - The filename
|
|
956
|
-
* @param {external:JSZip} [zip] - An optional {@link external:JSZip} object where to look
|
|
957
|
-
* for the file
|
|
958
|
-
* @returns {external:Promise}
|
|
959
|
-
*/
|
|
960
|
-
function getPathPromise(basePath, path, zip) {
|
|
961
|
-
if (zip) {
|
|
962
|
-
const fName = getRelativePath(basePath + path, zip.zipBasePath);
|
|
963
|
-
if (zip.files[fName]) {
|
|
964
|
-
return new Promise((resolve, reject) => {
|
|
965
|
-
zip.file(fName).async('base64').then(data => {
|
|
966
|
-
const ext = path.toLowerCase().split('.').pop();
|
|
967
|
-
const mime = settings.MIME_TYPES[ext] || 'application/octet-stream';
|
|
968
|
-
resolve(`data:${mime};base64,${data}`);
|
|
969
|
-
}).catch(reject);
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
return Promise.resolve(getPath(basePath, path));
|
|
974
|
-
};
|
|
975
|
-
|
|
976
|
-
/**
|
|
977
|
-
* Utility object that provides several methods to build simple and complex DOM objects
|
|
978
|
-
* @type {object}
|
|
979
|
-
*/
|
|
980
|
-
const $HTML = {
|
|
981
|
-
doubleCell: (a, b) => jquery__WEBPACK_IMPORTED_MODULE_0___default()('<tr/>').append(jquery__WEBPACK_IMPORTED_MODULE_0___default()('<td/>').html(a)).append(jquery__WEBPACK_IMPORTED_MODULE_0___default()('<td/>').html(b)),
|
|
982
|
-
p: txt => jquery__WEBPACK_IMPORTED_MODULE_0___default()('<p/>').html(txt),
|
|
983
|
-
td: (txt, className) => jquery__WEBPACK_IMPORTED_MODULE_0___default()('<td/>', className ? { class: className } : null).html(txt),
|
|
984
|
-
th: (txt, className) => jquery__WEBPACK_IMPORTED_MODULE_0___default()('<th/>', className ? { class: className } : null).html(txt),
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
/**
|
|
988
|
-
* Replaces `width`, `height` and `fill` attributes of a simple SVG image
|
|
989
|
-
* with the provided values
|
|
990
|
-
* @param {string} svg - The SVG image as XML string
|
|
991
|
-
* @param {string} [width] - Optional setting for "width" property
|
|
992
|
-
* @param {string} [height] - Optional setting for "height" property
|
|
993
|
-
* @param {string} [fill] - Optional setting for "fill" property
|
|
994
|
-
* @returns {string} - The resulting svg code
|
|
995
|
-
*/
|
|
996
|
-
function getSvg(svg, width, height, fill) {
|
|
997
|
-
if (width)
|
|
998
|
-
svg = svg.replace(/width=\"\d*\"/, `width="${width}"`);
|
|
999
|
-
if (height)
|
|
1000
|
-
svg = svg.replace(/height=\"\d*\"/, `height="${height}"`);
|
|
1001
|
-
if (fill)
|
|
1002
|
-
svg = svg.replace(/fill=\"[#A-Za-z0-9]*\"/, `fill="${fill}"`);
|
|
1003
|
-
return svg;
|
|
1004
|
-
};
|
|
1005
|
-
|
|
1006
|
-
/**
|
|
1007
|
-
* Encodes a svg expression into a {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs|data URI}
|
|
1008
|
-
* suitable for the `src` property of `img` elements, optionally changing its original size and fill values.
|
|
1009
|
-
* @param {string} svg - The SVG image as XML string
|
|
1010
|
-
* @param {string} [width] - Optional setting for "width" property
|
|
1011
|
-
* @param {string} [height] - Optional setting for "height" property
|
|
1012
|
-
* @param {string} [fill] - Optional setting for "fill" property
|
|
1013
|
-
* @returns {string} - The resulting Data URI
|
|
1014
|
-
*/
|
|
1015
|
-
function svgToURI(svg, width, height, fill) {
|
|
1016
|
-
return 'data:image/svg+xml;base64,' + window.btoa(getSvg(svg, width, height, fill));
|
|
1017
|
-
};
|
|
1018
|
-
|
|
1019
|
-
/**
|
|
1020
|
-
* Converts the given expression into a valid value for CSS size values
|
|
1021
|
-
* @param {string|number} exp - The expression to be evaluated. Can be a numeric value, `null` or `undefined`.
|
|
1022
|
-
* Positive values are in "px" units, negative ones are "%"
|
|
1023
|
-
* @param {object} css - An optional Object where the resulting expression (if any) will be saved
|
|
1024
|
-
* @param {string} key - The key under which the result will be stored in `css`
|
|
1025
|
-
* @param {string} def - Default value to be used when `exp` is `null` or `undefined`
|
|
1026
|
-
* @returns {string} - A valid CSS value, or `null` if it can't be found. Default units are `px`
|
|
1027
|
-
*/
|
|
1028
|
-
function toCssSize(exp, css, key, def) {
|
|
1029
|
-
const result = typeof exp === 'undefined' || exp === null ? null : isNaN(exp) ? exp : exp < 0 ? `${Math.abs(exp)}%` : `${exp}px`;
|
|
1030
|
-
if (css && key && (result || def))
|
|
1031
|
-
css[key] = result !== null ? result : def;
|
|
1032
|
-
return result;
|
|
1033
|
-
};
|
|
1034
|
-
|
|
1035
|
-
/**
|
|
1036
|
-
* Gets a clip of the give image data, in a URL base64 encoded format
|
|
1037
|
-
* @param {object} img - The binary data of the realized image, usually obtained from a {@link module:bads/MediaBagElement.MediaBagElement}
|
|
1038
|
-
* @param {module:AWT.Rectangle} rect - A rectangle containing the requested clip
|
|
1039
|
-
* @returns {string} - The URL with the image clip, as a PNG file encoded in base64
|
|
1040
|
-
*/
|
|
1041
|
-
function getImgClipUrl(img, rect) {
|
|
1042
|
-
const canvas = document.createElement('canvas');
|
|
1043
|
-
canvas.width = rect.dim.width;
|
|
1044
|
-
canvas.height = rect.dim.height;
|
|
1045
|
-
const ctx = canvas.getContext('2d');
|
|
1046
|
-
let result = '';
|
|
1047
|
-
try {
|
|
1048
|
-
ctx.drawImage(img, rect.pos.x, rect.pos.y, rect.dim.width, rect.dim.height, 0, 0, rect.dim.width, rect.dim.height);
|
|
1049
|
-
result = canvas.toDataURL();
|
|
1050
|
-
} catch (err) {
|
|
1051
|
-
// catch 'tainted canvases may not be exported' and other errors
|
|
1052
|
-
log('error', err);
|
|
1053
|
-
}
|
|
1054
|
-
return result;
|
|
1055
|
-
};
|
|
1056
|
-
|
|
1057
|
-
/**
|
|
1058
|
-
* Finds the nearest `head` or root node of a given HTMLElement, useful to place `<style/>` elements when
|
|
1059
|
-
* the main component of JClic is behind a shadow-root.
|
|
1060
|
-
* This method will be replaced by a call to [Node.getRootNode()](https://developer.mozilla.org/en-US/docs/Web/API/Node/getRootNode)
|
|
1061
|
-
* when fully supported by all major browsers.
|
|
1062
|
-
* @param {external:HTMLElement} [el] - The element from which to start the search
|
|
1063
|
-
* @returns {external:HTMLElement}
|
|
1064
|
-
*/
|
|
1065
|
-
function getRootHead(el) {
|
|
1066
|
-
if (el) {
|
|
1067
|
-
// Skip HTMLElements
|
|
1068
|
-
while (el.parentElement)
|
|
1069
|
-
el = el.parentElement;
|
|
1070
|
-
// Get the parent node of the last HTMLElement
|
|
1071
|
-
if (el instanceof HTMLElement)
|
|
1072
|
-
el = el.parentNode || el;
|
|
1073
|
-
// If the root node has a `head`, take it
|
|
1074
|
-
el = el['head'] || el;
|
|
1075
|
-
}
|
|
1076
|
-
return el || document.head;
|
|
1077
|
-
};
|
|
1078
|
-
|
|
1079
|
-
/**
|
|
1080
|
-
* Appends a stylesheet element to the `head` or root node nearest to the given `HTMLElement`.
|
|
1081
|
-
* @param {string} css - The content of the stylesheet
|
|
1082
|
-
* @param {module:JClicPlayer.JClicPlayer} [ps] - An optional `PlayStation` (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used as a base to find the root node
|
|
1083
|
-
* @returns {external:HTMLStyleElement} - The appended style element
|
|
1084
|
-
*/
|
|
1085
|
-
function appendStyleAtHead(css, ps) {
|
|
1086
|
-
const root = getRootHead(ps && ps.$topDiv ? ps.$topDiv[0] : null);
|
|
1087
|
-
const style = document.createElement('style');
|
|
1088
|
-
style.type = 'text/css';
|
|
1089
|
-
style.appendChild(document.createTextNode(css));
|
|
1090
|
-
return root.appendChild(style);
|
|
1091
|
-
};
|
|
1092
|
-
|
|
1093
|
-
/**
|
|
1094
|
-
* Traverses all the attributes defined in an Element, calling a function with its name and value as a parameters
|
|
1095
|
-
* @param {external:NamedNodeMap} attributes - The [Element.attributes](https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes)
|
|
1096
|
-
* object to be traversed
|
|
1097
|
-
* @param {function} callback - The function to be called for each [Attr](https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap)
|
|
1098
|
-
* object. It should take two parametres: `name` and `value`
|
|
1099
|
-
*/
|
|
1100
|
-
function attrForEach(attributes, callback) {
|
|
1101
|
-
for (let i = 0; i < attributes.length; i++)
|
|
1102
|
-
callback(attributes[i].name, attributes[i].value);
|
|
1103
|
-
};
|
|
1104
|
-
|
|
1105
|
-
/**
|
|
1106
|
-
* Recursive traversal of all nodes of the given object looking for children having the `childName` attribute
|
|
1107
|
-
* WARNING: Don't call this method on objects with circular dependencies!
|
|
1108
|
-
* @param {object} obj - The object to be analized
|
|
1109
|
-
* @param {string} childName - Name of the attribute to search for
|
|
1110
|
-
* @returns {object[]} - Array of children having the searched attribute
|
|
1111
|
-
*/
|
|
1112
|
-
function findParentsWithChild(obj, childName, _result = []) {
|
|
1113
|
-
if (obj[childName])
|
|
1114
|
-
_result.push(obj);
|
|
1115
|
-
else
|
|
1116
|
-
Object.values(obj).forEach(val => {
|
|
1117
|
-
if (typeof val === 'object')
|
|
1118
|
-
findParentsWithChild(val, childName, _result);
|
|
1119
|
-
});
|
|
1120
|
-
return _result;
|
|
1121
|
-
};
|
|
1122
|
-
|
|
1123
|
-
//
|
|
1124
|
-
// Functions useful to deal with caret position in `contentEditable` DOM elements
|
|
1125
|
-
//
|
|
1126
|
-
/**
|
|
1127
|
-
* Gets the caret position within the given element. Thanks to
|
|
1128
|
-
* {@link http://stackoverflow.com/users/96100/tim-down|Tim Down} answers in:
|
|
1129
|
-
* {@link http://stackoverflow.com/questions/4811822/get-a-ranges-start-and-end-offsets-relative-to-its-parent-container}
|
|
1130
|
-
* and {@link http://stackoverflow.com/questions/6240139/highlight-text-range-using-javascript/6242538}
|
|
1131
|
-
* @param {object} element - A DOM element
|
|
1132
|
-
* @returns {number}
|
|
1133
|
-
*/
|
|
1134
|
-
function getCaretCharacterOffsetWithin(element) {
|
|
1135
|
-
let caretOffset = 0;
|
|
1136
|
-
const doc = element.ownerDocument || element.document;
|
|
1137
|
-
const win = doc.defaultView || doc.parentWindow;
|
|
1138
|
-
let sel;
|
|
1139
|
-
if (typeof win.getSelection !== "undefined") {
|
|
1140
|
-
sel = win.getSelection();
|
|
1141
|
-
if (sel.rangeCount > 0) {
|
|
1142
|
-
const range = win.getSelection().getRangeAt(0);
|
|
1143
|
-
const preCaretRange = range.cloneRange();
|
|
1144
|
-
preCaretRange.selectNodeContents(element);
|
|
1145
|
-
preCaretRange.setEnd(range.endContainer, range.endOffset);
|
|
1146
|
-
caretOffset = preCaretRange.toString().length;
|
|
1147
|
-
}
|
|
1148
|
-
} else if ((sel = doc.selection) && sel.type !== "Control") {
|
|
1149
|
-
const textRange = sel.createRange();
|
|
1150
|
-
const preCaretTextRange = doc.body.createTextRange();
|
|
1151
|
-
preCaretTextRange.moveToElementText(element);
|
|
1152
|
-
preCaretTextRange.setEndPoint("EndToEnd", textRange);
|
|
1153
|
-
caretOffset = preCaretTextRange.text.length;
|
|
1154
|
-
}
|
|
1155
|
-
return caretOffset;
|
|
1156
|
-
};
|
|
1157
|
-
|
|
1158
|
-
/**
|
|
1159
|
-
* Utility function called by {@link module:Utils.getCaretCharacterOffsetWithin}
|
|
1160
|
-
* @param {object} node - A text node
|
|
1161
|
-
* @returns {object[]}
|
|
1162
|
-
*/
|
|
1163
|
-
function getTextNodesIn(node) {
|
|
1164
|
-
const textNodes = [];
|
|
1165
|
-
if (node.nodeType === 3) {
|
|
1166
|
-
textNodes.push(node);
|
|
1167
|
-
} else {
|
|
1168
|
-
const children = node.childNodes;
|
|
1169
|
-
for (let i = 0, len = children.length; i < len; ++i) {
|
|
1170
|
-
textNodes.push.apply(textNodes, getTextNodesIn(children[i]));
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
return textNodes;
|
|
1174
|
-
};
|
|
1175
|
-
|
|
1176
|
-
/**
|
|
1177
|
-
* Sets the selection range (or the cursor position, when `start` and `end` are the same) to a
|
|
1178
|
-
* specific position inside a DOM element.
|
|
1179
|
-
* @param {object} el - The DOM element where to set the cursor
|
|
1180
|
-
* @param {number} start - The start position of the selection (or cursor position)
|
|
1181
|
-
* @param {number} end - The end position of the selection. When null or identical to `start`,
|
|
1182
|
-
* indicates a cursor position.
|
|
1183
|
-
*/
|
|
1184
|
-
function setSelectionRange(el, start, end) {
|
|
1185
|
-
if (isNullOrUndef(end))
|
|
1186
|
-
end = start;
|
|
1187
|
-
if (document.createRange && window.getSelection) {
|
|
1188
|
-
const range = document.createRange();
|
|
1189
|
-
range.selectNodeContents(el);
|
|
1190
|
-
const textNodes = getTextNodesIn(el);
|
|
1191
|
-
let foundStart = false;
|
|
1192
|
-
let charCount = 0, endCharCount, textNode;
|
|
1193
|
-
|
|
1194
|
-
for (let i = 0; i < textNodes.length; i++) {
|
|
1195
|
-
textNode = textNodes[i];
|
|
1196
|
-
endCharCount = charCount + textNode.length;
|
|
1197
|
-
if (!foundStart && start >= charCount &&
|
|
1198
|
-
(start < endCharCount ||
|
|
1199
|
-
start === endCharCount && i + 1 <= textNodes.length)) {
|
|
1200
|
-
range.setStart(textNode, start - charCount);
|
|
1201
|
-
foundStart = true;
|
|
1202
|
-
}
|
|
1203
|
-
if (foundStart && end <= endCharCount) {
|
|
1204
|
-
range.setEnd(textNode, end - charCount);
|
|
1205
|
-
break;
|
|
1206
|
-
}
|
|
1207
|
-
charCount = endCharCount;
|
|
1208
|
-
}
|
|
1209
|
-
const sel = window.getSelection();
|
|
1210
|
-
sel.removeAllRanges();
|
|
1211
|
-
sel.addRange(range);
|
|
1212
|
-
} else if (document.selection && document.body.createTextRange) {
|
|
1213
|
-
const textRange = document.body.createTextRange();
|
|
1214
|
-
textRange.moveToElementText(el);
|
|
1215
|
-
textRange.collapse(true);
|
|
1216
|
-
textRange.moveEnd('character', end);
|
|
1217
|
-
textRange.moveStart('character', start);
|
|
1218
|
-
textRange.select();
|
|
1219
|
-
}
|
|
1220
|
-
};
|
|
1221
|
-
|
|
1222
|
-
/**
|
|
1223
|
-
* Performs multiple replacements on the provided string
|
|
1224
|
-
* See: https://stackoverflow.com/questions/2501435/replacing-multiple-patterns-in-a-block-of-data
|
|
1225
|
-
* @param {Object[]} replacements - Array of pairs formed by an "expression" (regexp or string) and a "value" (string) to replace the fragments found
|
|
1226
|
-
* @param {String} str - The string to be checked for replacements
|
|
1227
|
-
* @returns {String} - The original string with the fragments found already replaced
|
|
1228
|
-
*/
|
|
1229
|
-
function mReplace(replacements, str) {
|
|
1230
|
-
return replacements.reduce((result, [exp, replacement]) => result.replace(exp, replacement), str);
|
|
1231
|
-
};
|
|
1232
|
-
|
|
1233
|
-
/**
|
|
1234
|
-
* Global constants
|
|
1235
|
-
* @const
|
|
1236
|
-
*/
|
|
1237
|
-
const settings = {
|
|
1238
|
-
// JClic.js Version
|
|
1239
|
-
VERSION: _GlobalData_js__WEBPACK_IMPORTED_MODULE_3__["default"].version,
|
|
1240
|
-
// Check if we are running on NodeJS with JSDOM
|
|
1241
|
-
NODEJS: typeof window === 'undefined' || window?.navigator?.userAgent?.includes('jsdom'),
|
|
1242
|
-
// layout constants
|
|
1243
|
-
AB: 0, BA: 1, AUB: 2, BUA: 3,
|
|
1244
|
-
LAYOUT_NAMES: ['AB', 'BA', 'AUB', 'BUA'],
|
|
1245
|
-
DEFAULT_WIDTH: 400,
|
|
1246
|
-
DEFAULT_HEIGHT: 300,
|
|
1247
|
-
MINIMUM_WIDTH: 40,
|
|
1248
|
-
MINIMUM_HEIGHT: 40,
|
|
1249
|
-
DEFAULT_NAME: '---',
|
|
1250
|
-
DEFAULT_MARGIN: 8,
|
|
1251
|
-
DEFAULT_SHUFFLES: 31,
|
|
1252
|
-
DEFAULT_GRID_ELEMENT_SIZE: 20,
|
|
1253
|
-
MIN_CELL_SIZE: 10,
|
|
1254
|
-
//DEFAULT_BG_COLOR: '#D3D3D3', // LightGray
|
|
1255
|
-
DEFAULT_BG_COLOR: '#C0C0C0', // LightGray
|
|
1256
|
-
ACTIONS: {
|
|
1257
|
-
ACTION_MATCH: 'MATCH', ACTION_PLACE: 'PLACE',
|
|
1258
|
-
ACTION_WRITE: 'WRITE', ACTION_SELECT: 'SELECT', ACTION_HELP: 'HELP'
|
|
1259
|
-
},
|
|
1260
|
-
PREVIOUS: 0, MAIN: 1, END: 2, END_ERROR: 3, NUM_MSG: 4,
|
|
1261
|
-
MSG_TYPE: ['previous', 'initial', 'final', 'finalError'],
|
|
1262
|
-
RANDOM_CHARS: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
1263
|
-
NUM_COUNTERS: 3,
|
|
1264
|
-
MAX_RECORD_LENGTH: 180,
|
|
1265
|
-
// BoxBase defaults
|
|
1266
|
-
BoxBase: {
|
|
1267
|
-
REDUCE_FONT_STEP: 1.0,
|
|
1268
|
-
MIN_FONT_SIZE: 8,
|
|
1269
|
-
STROKE: 1,
|
|
1270
|
-
AC_MARGIN: 6,
|
|
1271
|
-
//BACK_COLOR: 'lightgray',
|
|
1272
|
-
BACK_COLOR: '#C0C0C0',
|
|
1273
|
-
TEXT_COLOR: 'black',
|
|
1274
|
-
SHADOW_COLOR: 'gray',
|
|
1275
|
-
INACTIVE_COLOR: 'gray',
|
|
1276
|
-
ALTERNATIVE_COLOR: 'gray',
|
|
1277
|
-
BORDER_COLOR: 'black',
|
|
1278
|
-
BORDER_STROKE_WIDTH: 0.75,
|
|
1279
|
-
MARKER_STROKE_WIDTH: 2.75
|
|
1280
|
-
},
|
|
1281
|
-
FILE_TYPES: {
|
|
1282
|
-
image: 'gif,jpg,png,jpeg,bmp,ico,svg',
|
|
1283
|
-
audio: 'wav,mp3,ogg,oga,au,aiff,flac',
|
|
1284
|
-
video: 'avi,mov,mpeg,mp4,ogv,m4v,webm',
|
|
1285
|
-
font: 'ttf,otf,eot,woff,woff2',
|
|
1286
|
-
midi: 'mid,midi',
|
|
1287
|
-
anim: 'swf',
|
|
1288
|
-
// Used in custom skins
|
|
1289
|
-
xml: 'xml'
|
|
1290
|
-
},
|
|
1291
|
-
MIME_TYPES: {
|
|
1292
|
-
xml: 'text/xml',
|
|
1293
|
-
gif: 'image/gif',
|
|
1294
|
-
jpg: 'image/jpeg',
|
|
1295
|
-
jpeg: 'image/jpeg',
|
|
1296
|
-
png: 'image/png',
|
|
1297
|
-
bmp: 'image/bmp',
|
|
1298
|
-
svg: 'image/svg+xml',
|
|
1299
|
-
ico: 'image/x-icon',
|
|
1300
|
-
wav: 'audio/wav',
|
|
1301
|
-
mp3: 'audio/mpeg',
|
|
1302
|
-
mp4: 'video/mp4',
|
|
1303
|
-
m4v: 'video/mp4',
|
|
1304
|
-
ogg: 'audio/ogg',
|
|
1305
|
-
oga: 'audio/ogg',
|
|
1306
|
-
ogv: 'video/ogg',
|
|
1307
|
-
webm: 'video/webm',
|
|
1308
|
-
au: 'audio/basic',
|
|
1309
|
-
aiff: 'audio/x-aiff',
|
|
1310
|
-
flac: 'audio/flac',
|
|
1311
|
-
avi: 'video/avi',
|
|
1312
|
-
mov: 'video/quicktime',
|
|
1313
|
-
mpeg: 'video/mpeg',
|
|
1314
|
-
ttf: 'application/font-sfnt',
|
|
1315
|
-
otf: 'application/font-sfnt',
|
|
1316
|
-
eot: ' application/vnd.ms-fontobject',
|
|
1317
|
-
woff: 'application/font-woff',
|
|
1318
|
-
woff2: 'application/font-woff2',
|
|
1319
|
-
swf: 'application/x-shockwave-flash',
|
|
1320
|
-
mid: 'audio/midi',
|
|
1321
|
-
midi: 'audio/midi'
|
|
1322
|
-
},
|
|
1323
|
-
// Global settings susceptible to be modified
|
|
1324
|
-
COMPRESS_IMAGES: true,
|
|
1325
|
-
// Keyboard key codes
|
|
1326
|
-
VK: {
|
|
1327
|
-
LEFT: 37,
|
|
1328
|
-
UP: 38,
|
|
1329
|
-
RIGHT: 39,
|
|
1330
|
-
DOWN: 40
|
|
1331
|
-
},
|
|
1332
|
-
// Flag to indicate that we are running on a touch device
|
|
1333
|
-
TOUCH_DEVICE: false,
|
|
1334
|
-
// Amount of time (in milliseconds) to wait before a media resource is loaded
|
|
1335
|
-
LOAD_TIMEOUT: 10000,
|
|
1336
|
-
// Number of points to be calculated as polygon vertexs when simplifying bezier curves
|
|
1337
|
-
BEZIER_POINTS: 4,
|
|
1338
|
-
// Check if canvas accessibility features are enabled
|
|
1339
|
-
// See: http://codepen.io/francesc/pen/amwvRp
|
|
1340
|
-
// UPDATED May 2020: Detection removed since Canvas HitRegions have been deprecated
|
|
1341
|
-
// See: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility
|
|
1342
|
-
//
|
|
1343
|
-
// CANVAS_HITREGIONS: typeof CanvasRenderingContext2D !== 'undefined' && typeof CanvasRenderingContext2D.prototype.addHitRegion === 'function',
|
|
1344
|
-
// CANVAS_HITREGIONS_FOCUS: typeof CanvasRenderingContext2D !== 'undefined' && typeof CanvasRenderingContext2D.prototype.drawFocusIfNeeded === 'function',
|
|
1345
|
-
//
|
|
1346
|
-
CANVAS_DRAW_FOCUS: typeof window !== 'undefined' && typeof window?.CanvasRenderingContext2D?.prototype?.drawFocusIfNeeded === 'function',
|
|
1347
|
-
// See: https://emptycharacter.com/
|
|
1348
|
-
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
|
|
1349
|
-
WHITESPACES: ' \f\n\r\t\v\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202f\u205f\u3000\ufeff',
|
|
1350
|
-
};
|
|
1351
|
-
settings.SEPARATORS = `${settings.WHITESPACES}.,;-|`;
|
|
1352
|
-
settings.WORD_DELIMITERS = `${settings.SEPARATORS}…_<>"“”«»'\xB4\x60\u2018\u2019\u2022~+\u2013\u2014\u2015=%¿?¡!:/\\()[]{}$£€`;
|
|
1353
|
-
|
|
1354
|
-
/**
|
|
1355
|
-
* Miscellaneous utility functions and constants
|
|
1356
|
-
*/
|
|
1357
|
-
const Utils = {
|
|
1358
|
-
pkg,
|
|
1359
|
-
settings,
|
|
1360
|
-
getMsg,
|
|
1361
|
-
LOG_LEVELS,
|
|
1362
|
-
LOG_PRINT_LABELS,
|
|
1363
|
-
LOG_OPTIONS,
|
|
1364
|
-
init,
|
|
1365
|
-
setLogLevel,
|
|
1366
|
-
log,
|
|
1367
|
-
getBoolean,
|
|
1368
|
-
getVal,
|
|
1369
|
-
getNumber,
|
|
1370
|
-
getPercent,
|
|
1371
|
-
zp,
|
|
1372
|
-
getHMStime,
|
|
1373
|
-
getDateTime,
|
|
1374
|
-
parseOldDate,
|
|
1375
|
-
cleanOldLanguageTag,
|
|
1376
|
-
FALSE,
|
|
1377
|
-
TRUE,
|
|
1378
|
-
DEFAULT,
|
|
1379
|
-
getTriState,
|
|
1380
|
-
fillString,
|
|
1381
|
-
isNullOrUndef,
|
|
1382
|
-
isEquivalent,
|
|
1383
|
-
getXmlText,
|
|
1384
|
-
parseXmlNode,
|
|
1385
|
-
getXmlNodeText,
|
|
1386
|
-
reduceTextsToStrings,
|
|
1387
|
-
cssToString,
|
|
1388
|
-
checkColor,
|
|
1389
|
-
colorHasTransparency,
|
|
1390
|
-
cloneObject,
|
|
1391
|
-
normalizeObject,
|
|
1392
|
-
getAttr,
|
|
1393
|
-
getValue,
|
|
1394
|
-
isEmpty,
|
|
1395
|
-
setAttr,
|
|
1396
|
-
buildObj,
|
|
1397
|
-
isSeparator,
|
|
1398
|
-
isWordDelimiter,
|
|
1399
|
-
stringToWords,
|
|
1400
|
-
roundTo,
|
|
1401
|
-
fx,
|
|
1402
|
-
compareMultipleOptions,
|
|
1403
|
-
endsWith,
|
|
1404
|
-
startsWith,
|
|
1405
|
-
nSlash,
|
|
1406
|
-
isURL,
|
|
1407
|
-
getBasePath,
|
|
1408
|
-
getRelativePath,
|
|
1409
|
-
getPath,
|
|
1410
|
-
getPathPromise,
|
|
1411
|
-
$HTML,
|
|
1412
|
-
getSvg,
|
|
1413
|
-
svgToURI,
|
|
1414
|
-
toCssSize,
|
|
1415
|
-
getImgClipUrl,
|
|
1416
|
-
getRootHead,
|
|
1417
|
-
appendStyleAtHead,
|
|
1418
|
-
attrForEach,
|
|
1419
|
-
findParentsWithChild,
|
|
1420
|
-
getCaretCharacterOffsetWithin,
|
|
1421
|
-
getTextNodesIn,
|
|
1422
|
-
setSelectionRange
|
|
1423
|
-
};
|
|
1424
|
-
|
|
1425
|
-
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Utils);
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
/***/ })
|
|
1429
|
-
|
|
1430
|
-
};
|
|
1431
|
-
;
|
|
1432
|
-
//# sourceMappingURL=1253.jclic-node.js.map
|