@qti-components/processing 1.3.1 → 1.3.3
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/dist/components/index.d.ts +18 -0
- package/dist/components/index.js +18 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/qti-and/qti-and.d.ts +8 -0
- package/dist/components/qti-and/qti-and.js +8 -0
- package/dist/components/qti-and/qti-and.js.map +1 -1
- package/dist/components/qti-any-n/qti-any-n.d.ts +15 -0
- package/dist/components/qti-any-n/qti-any-n.js +61 -0
- package/dist/components/qti-any-n/qti-any-n.js.map +1 -0
- package/dist/components/qti-container-size/qti-container-size.d.ts +5 -5
- package/dist/components/qti-container-size/qti-container-size.js +5 -5
- package/dist/components/qti-container-size/qti-container-size.js.map +1 -1
- package/dist/components/qti-correct/qti-correct.d.ts +8 -0
- package/dist/components/qti-correct/qti-correct.js +8 -0
- package/dist/components/qti-correct/qti-correct.js.map +1 -1
- package/dist/components/qti-default/qti-default.d.ts +5 -5
- package/dist/components/qti-default/qti-default.js +5 -5
- package/dist/components/qti-default/qti-default.js.map +1 -1
- package/dist/components/qti-delete/qti-delete.d.ts +8 -0
- package/dist/components/qti-delete/qti-delete.js +8 -0
- package/dist/components/qti-delete/qti-delete.js.map +1 -1
- package/dist/components/qti-divide/qti-divide.d.ts +13 -0
- package/dist/components/qti-divide/qti-divide.js +50 -0
- package/dist/components/qti-divide/qti-divide.js.map +1 -0
- package/dist/components/qti-duration-gte/qti-duration-gte.d.ts +5 -0
- package/dist/components/qti-duration-gte/qti-duration-gte.js +45 -0
- package/dist/components/qti-duration-gte/qti-duration-gte.js.map +1 -0
- package/dist/components/qti-duration-lt/qti-duration-lt.d.ts +13 -0
- package/dist/components/qti-duration-lt/qti-duration-lt.js +53 -0
- package/dist/components/qti-duration-lt/qti-duration-lt.js.map +1 -0
- package/dist/components/qti-equal/qti-equal.d.ts +9 -0
- package/dist/components/qti-equal/qti-equal.js +15 -0
- package/dist/components/qti-equal/qti-equal.js.map +1 -1
- package/dist/components/qti-equal-rounded/qti-equal-rounded.d.ts +9 -0
- package/dist/components/qti-equal-rounded/qti-equal-rounded.js +9 -0
- package/dist/components/qti-equal-rounded/qti-equal-rounded.js.map +1 -1
- package/dist/components/qti-field-value/qti-field-value.d.ts +8 -0
- package/dist/components/qti-field-value/qti-field-value.js +8 -0
- package/dist/components/qti-field-value/qti-field-value.js.map +1 -1
- package/dist/components/qti-index/qti-index.d.ts +8 -0
- package/dist/components/qti-index/qti-index.js +8 -0
- package/dist/components/qti-index/qti-index.js.map +1 -1
- package/dist/components/qti-inside/qti-inside.d.ts +7 -0
- package/dist/components/qti-inside/qti-inside.js +141 -0
- package/dist/components/qti-inside/qti-inside.js.map +1 -0
- package/dist/components/qti-integer-divide/qti-integer-divide.d.ts +13 -0
- package/dist/components/qti-integer-divide/qti-integer-divide.js +48 -0
- package/dist/components/qti-integer-divide/qti-integer-divide.js.map +1 -0
- package/dist/components/qti-integer-modulus/qti-integer-modulus.d.ts +13 -0
- package/dist/components/qti-integer-modulus/qti-integer-modulus.js +48 -0
- package/dist/components/qti-integer-modulus/qti-integer-modulus.js.map +1 -0
- package/dist/components/qti-integer-to-float/qti-integer-to-float.d.ts +12 -0
- package/dist/components/qti-integer-to-float/qti-integer-to-float.js +38 -0
- package/dist/components/qti-integer-to-float/qti-integer-to-float.js.map +1 -0
- package/dist/components/qti-is-null/qti-is-null.d.ts +8 -0
- package/dist/components/qti-is-null/qti-is-null.js +8 -2
- package/dist/components/qti-is-null/qti-is-null.js.map +1 -1
- package/dist/components/qti-lcm/qti-lcm.d.ts +5 -0
- package/dist/components/qti-lcm/qti-lcm.js +71 -0
- package/dist/components/qti-lcm/qti-lcm.js.map +1 -0
- package/dist/components/qti-map-response/qti-map-response.d.ts +8 -0
- package/dist/components/qti-map-response/qti-map-response.js +8 -0
- package/dist/components/qti-map-response/qti-map-response.js.map +1 -1
- package/dist/components/qti-match/qti-match.d.ts +8 -0
- package/dist/components/qti-match/qti-match.js +8 -0
- package/dist/components/qti-match/qti-match.js.map +1 -1
- package/dist/components/qti-max/qti-max.d.ts +13 -0
- package/dist/components/qti-max/qti-max.js +46 -0
- package/dist/components/qti-max/qti-max.js.map +1 -0
- package/dist/components/qti-min/qti-min.d.ts +13 -0
- package/dist/components/qti-min/qti-min.js +46 -0
- package/dist/components/qti-min/qti-min.js.map +1 -0
- package/dist/components/qti-not/qti-not.d.ts +8 -0
- package/dist/components/qti-not/qti-not.js +8 -0
- package/dist/components/qti-not/qti-not.js.map +1 -1
- package/dist/components/qti-or/qti-or.d.ts +8 -0
- package/dist/components/qti-or/qti-or.js +8 -0
- package/dist/components/qti-or/qti-or.js.map +1 -1
- package/dist/components/qti-pattern-match/qti-pattern-match.d.ts +13 -0
- package/dist/components/qti-pattern-match/qti-pattern-match.js +53 -0
- package/dist/components/qti-pattern-match/qti-pattern-match.js.map +1 -0
- package/dist/components/qti-product/qti-product.d.ts +8 -0
- package/dist/components/qti-product/qti-product.js +8 -0
- package/dist/components/qti-product/qti-product.js.map +1 -1
- package/dist/components/qti-repeat/qti-repeat.d.ts +15 -0
- package/dist/components/qti-repeat/qti-repeat.js +113 -0
- package/dist/components/qti-repeat/qti-repeat.js.map +1 -0
- package/dist/components/qti-round/qti-round.d.ts +4 -5
- package/dist/components/qti-round/qti-round.js +4 -5
- package/dist/components/qti-round/qti-round.js.map +1 -1
- package/dist/components/qti-set-correct-response/qti-set-correct-response.d.ts +24 -0
- package/dist/components/qti-set-correct-response/qti-set-correct-response.js +77 -0
- package/dist/components/qti-set-correct-response/qti-set-correct-response.js.map +1 -0
- package/dist/components/qti-set-template-value/qti-set-template-value.d.ts +24 -0
- package/dist/components/qti-set-template-value/qti-set-template-value.js +81 -0
- package/dist/components/qti-set-template-value/qti-set-template-value.js.map +1 -0
- package/dist/components/qti-stats-operator/qti-stats-operator.d.ts +15 -0
- package/dist/components/qti-stats-operator/qti-stats-operator.js +78 -0
- package/dist/components/qti-stats-operator/qti-stats-operator.js.map +1 -0
- package/dist/components/qti-substring/qti-substring.d.ts +13 -0
- package/dist/components/qti-substring/qti-substring.js +51 -0
- package/dist/components/qti-substring/qti-substring.js.map +1 -0
- package/dist/components/qti-subtract/qti-subtract.d.ts +8 -0
- package/dist/components/qti-subtract/qti-subtract.js +8 -0
- package/dist/components/qti-subtract/qti-subtract.js.map +1 -1
- package/dist/components/qti-sum/qti-sum.d.ts +8 -0
- package/dist/components/qti-sum/qti-sum.js +8 -0
- package/dist/components/qti-sum/qti-sum.js.map +1 -1
- package/dist/components/qti-truncate/qti-truncate.d.ts +12 -0
- package/dist/components/qti-truncate/qti-truncate.js +38 -0
- package/dist/components/qti-truncate/qti-truncate.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qti-pattern-match.js","sourceRoot":"","sources":["../../../src/components/qti-pattern-match/qti-pattern-match.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,eAAgB,SAAQ,aAA6B;IAAlE;;QAC8B,YAAO,GAAG,EAAE,CAAC;IA+B3C,CAAC;IA7BiB,SAAS;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QAE5D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACzE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACvE,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;YAC/D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,uDAAuD,EAAE,KAAK,CAAC,CAAC;YAC9E,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AA/B6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDAAc;AAiC3C,cAAc,CAAC,MAAM,CAAC,mBAAmB,EAAE,eAAe,CAAC,CAAC","sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-pattern-match operator checks a string against a regular expression.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#patternMatch\n *\n * Takes 1 string sub-expression; 'pattern' attribute contains the regex.\n * Returns true if the string matches the pattern, false otherwise.\n * Special cases: Returns NULL if sub-expression is NULL.\n */\nexport class QtiPatternMatch extends QtiExpression<boolean | null> {\n @property({ type: String }) pattern = '';\n\n public override getResult(): boolean | null {\n const variables = this.getVariables() as ResponseVariable[];\n\n if (variables.length !== 1) {\n console.error('qti-pattern-match requires exactly one child expression');\n return null;\n }\n\n if (!this.pattern) {\n console.error('qti-pattern-match requires a pattern attribute');\n return null;\n }\n\n const variable = variables[0];\n if (variable.cardinality !== 'single' || Array.isArray(variable.value)) {\n console.error('qti-pattern-match requires single cardinality');\n return null;\n }\n if (variable.value === null || variable.value === undefined) {\n return null;\n }\n\n try {\n return new RegExp(this.pattern).test(variable.value.toString());\n } catch (error) {\n console.error('qti-pattern-match requires a valid regular expression', error);\n return null;\n }\n }\n}\n\ncustomElements.define('qti-pattern-match', QtiPatternMatch);\n"]}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { QtiExpression } from '@qti-components/base';
|
|
2
|
+
/**
|
|
3
|
+
* @summary The qti-product operator calculates the product of multiple numerical values.
|
|
4
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#product
|
|
5
|
+
*
|
|
6
|
+
* Takes 1 or more sub-expressions with numerical base-types and any cardinality.
|
|
7
|
+
* Returns a single float (or integer if all arguments are integers).
|
|
8
|
+
* Special cases: Returns NULL if any sub-expression is NULL.
|
|
9
|
+
*/
|
|
2
10
|
export declare class QtiProduct extends QtiExpression<number> {
|
|
3
11
|
getResult(): number;
|
|
4
12
|
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { QtiExpression } from '@qti-components/base';
|
|
2
|
+
/**
|
|
3
|
+
* @summary The qti-product operator calculates the product of multiple numerical values.
|
|
4
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#product
|
|
5
|
+
*
|
|
6
|
+
* Takes 1 or more sub-expressions with numerical base-types and any cardinality.
|
|
7
|
+
* Returns a single float (or integer if all arguments are integers).
|
|
8
|
+
* Special cases: Returns NULL if any sub-expression is NULL.
|
|
9
|
+
*/
|
|
2
10
|
export class QtiProduct extends QtiExpression {
|
|
3
11
|
getResult() {
|
|
4
12
|
const values = this.getVariables();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qti-product.js","sourceRoot":"","sources":["../../../src/components/qti-product/qti-product.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD,MAAM,OAAO,UAAW,SAAQ,aAAqB;IACnC,SAAS;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,EAAE;YAC1D,IAAI,YAAY,CAAC,QAAQ,IAAI,OAAO,IAAI,YAAY,CAAC,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAC3E,IAAI,CAAC;oBACH,OAAO,WAAW,GAAG,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACjE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,wBAAwB,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,OAAO,WAAW,CAAC;QACrB,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\nexport class QtiProduct extends QtiExpression<number> {\n public override getResult() {\n const values = this.getVariables() as ResponseVariable[];\n const product = values.reduce((accumulator, currentValue) => {\n if (currentValue.baseType == 'float' || currentValue.baseType == 'integer') {\n try {\n return accumulator * parseFloat(currentValue.value.toString());\n } catch (error) {\n console.warn(`can not convert to number`);\n }\n } else {\n console.warn(`has another baseType ${currentValue.baseType}`);\n }\n return accumulator;\n }, 1);\n return product;\n }\n}\n\ncustomElements.define('qti-product', QtiProduct);\n"]}
|
|
1
|
+
{"version":3,"file":"qti-product.js","sourceRoot":"","sources":["../../../src/components/qti-product/qti-product.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,UAAW,SAAQ,aAAqB;IACnC,SAAS;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,EAAE;YAC1D,IAAI,YAAY,CAAC,QAAQ,IAAI,OAAO,IAAI,YAAY,CAAC,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAC3E,IAAI,CAAC;oBACH,OAAO,WAAW,GAAG,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACjE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,wBAAwB,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,OAAO,WAAW,CAAC;QACrB,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-product operator calculates the product of multiple numerical values.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#product\n *\n * Takes 1 or more sub-expressions with numerical base-types and any cardinality.\n * Returns a single float (or integer if all arguments are integers).\n * Special cases: Returns NULL if any sub-expression is NULL.\n */\nexport class QtiProduct extends QtiExpression<number> {\n public override getResult() {\n const values = this.getVariables() as ResponseVariable[];\n const product = values.reduce((accumulator, currentValue) => {\n if (currentValue.baseType == 'float' || currentValue.baseType == 'integer') {\n try {\n return accumulator * parseFloat(currentValue.value.toString());\n } catch (error) {\n console.warn(`can not convert to number`);\n }\n } else {\n console.warn(`has another baseType ${currentValue.baseType}`);\n }\n return accumulator;\n }, 1);\n return product;\n }\n}\n\ncustomElements.define('qti-product', QtiProduct);\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { QtiExpression } from '@qti-components/base';
|
|
2
|
+
import type { ResponseVariable } from '@qti-components/base';
|
|
3
|
+
/**
|
|
4
|
+
* @summary The qti-repeat operator generates a container by repeating an expression.
|
|
5
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#repeat
|
|
6
|
+
*
|
|
7
|
+
* Attributes 'number-repeats' determines the count of iterations.
|
|
8
|
+
* Returns an ordered container filled with results of the evaluated sub-expressions.
|
|
9
|
+
* Special cases: Returns NULL if number-repeats < 1; ignores evaluated NULL values.
|
|
10
|
+
*/
|
|
11
|
+
export declare class QtiRepeat extends QtiExpression<ResponseVariable[]> {
|
|
12
|
+
#private;
|
|
13
|
+
numberRepeats: string;
|
|
14
|
+
getResult(): ResponseVariable[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { property } from 'lit/decorators.js';
|
|
8
|
+
import { QtiExpression } from '@qti-components/base';
|
|
9
|
+
/**
|
|
10
|
+
* @summary The qti-repeat operator generates a container by repeating an expression.
|
|
11
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#repeat
|
|
12
|
+
*
|
|
13
|
+
* Attributes 'number-repeats' determines the count of iterations.
|
|
14
|
+
* Returns an ordered container filled with results of the evaluated sub-expressions.
|
|
15
|
+
* Special cases: Returns NULL if number-repeats < 1; ignores evaluated NULL values.
|
|
16
|
+
*/
|
|
17
|
+
export class QtiRepeat extends QtiExpression {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(...arguments);
|
|
20
|
+
this.numberRepeats = '';
|
|
21
|
+
}
|
|
22
|
+
getResult() {
|
|
23
|
+
const count = this.#resolveRepeatCount();
|
|
24
|
+
if (count <= 0) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
const expression = this.firstElementChild;
|
|
28
|
+
if (!expression) {
|
|
29
|
+
console.warn('qti-repeat: missing child expression');
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const results = [];
|
|
33
|
+
for (let i = 0; i < count; i++) {
|
|
34
|
+
const value = expression.calculate();
|
|
35
|
+
const variable = this.#toResponseVariable(value);
|
|
36
|
+
if (variable) {
|
|
37
|
+
results.push(variable);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
#resolveRepeatCount() {
|
|
43
|
+
if (!this.numberRepeats) {
|
|
44
|
+
console.warn('qti-repeat: missing number-repeats attribute');
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
const numericCount = parseInt(this.numberRepeats, 10);
|
|
48
|
+
if (!Number.isNaN(numericCount)) {
|
|
49
|
+
return numericCount;
|
|
50
|
+
}
|
|
51
|
+
const identifier = this.numberRepeats;
|
|
52
|
+
const variable = this.context?.variables?.find(v => v.identifier === identifier);
|
|
53
|
+
if (!variable) {
|
|
54
|
+
console.warn(`qti-repeat: unknown identifier "${identifier}"`);
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
const rawValue = Array.isArray(variable.value) ? variable.value[0] : variable.value;
|
|
58
|
+
const resolvedCount = parseInt(rawValue?.toString() ?? '', 10);
|
|
59
|
+
if (Number.isNaN(resolvedCount)) {
|
|
60
|
+
console.warn(`qti-repeat: invalid repeat count from "${identifier}"`);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
return resolvedCount;
|
|
64
|
+
}
|
|
65
|
+
#toResponseVariable(value) {
|
|
66
|
+
if (value === null || value === undefined) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (typeof value === 'number') {
|
|
70
|
+
return {
|
|
71
|
+
identifier: '',
|
|
72
|
+
cardinality: 'single',
|
|
73
|
+
baseType: Number.isInteger(value) ? 'integer' : 'float',
|
|
74
|
+
value: value.toString(),
|
|
75
|
+
type: 'response'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (typeof value === 'string') {
|
|
79
|
+
const numericValue = parseFloat(value);
|
|
80
|
+
if (!Number.isNaN(numericValue)) {
|
|
81
|
+
return {
|
|
82
|
+
identifier: '',
|
|
83
|
+
cardinality: 'single',
|
|
84
|
+
baseType: Number.isInteger(numericValue) ? 'integer' : 'float',
|
|
85
|
+
value: value.toString(),
|
|
86
|
+
type: 'response'
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (value && typeof value === 'object' && 'value' in value) {
|
|
91
|
+
const responseValue = value.value;
|
|
92
|
+
return {
|
|
93
|
+
identifier: '',
|
|
94
|
+
cardinality: 'single',
|
|
95
|
+
baseType: value.baseType ?? 'string',
|
|
96
|
+
value: responseValue !== null && responseValue !== undefined ? responseValue.toString() : null,
|
|
97
|
+
type: 'response'
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
identifier: '',
|
|
102
|
+
cardinality: 'single',
|
|
103
|
+
baseType: 'string',
|
|
104
|
+
value: value.toString(),
|
|
105
|
+
type: 'response'
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
__decorate([
|
|
110
|
+
property({ type: String, attribute: 'number-repeats' })
|
|
111
|
+
], QtiRepeat.prototype, "numberRepeats", void 0);
|
|
112
|
+
customElements.define('qti-repeat', QtiRepeat);
|
|
113
|
+
//# sourceMappingURL=qti-repeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qti-repeat.js","sourceRoot":"","sources":["../../../src/components/qti-repeat/qti-repeat.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,SAAU,SAAQ,aAAiC;IAAhE;;QAC2D,kBAAa,GAAW,EAAE,CAAC;IAsGtF,CAAC;IApGiB,SAAS;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YACf,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAkD,CAAC;QAC3E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;YACrD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAuB,EAAE,CAAC;QACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;YACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,mBAAmB;QACjB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;YAC7D,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;YAChC,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;QACjF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,mCAAmC,UAAU,GAAG,CAAC,CAAC;YAC/D,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QACpF,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAE/D,IAAI,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,0CAA0C,UAAU,GAAG,CAAC,CAAC;YACtE,OAAO,CAAC,CAAC;QACX,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,mBAAmB,CAAC,KAAc;QAChC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO;gBACL,UAAU,EAAE,EAAE;gBACd,WAAW,EAAE,QAAQ;gBACrB,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;gBACvD,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;gBACvB,IAAI,EAAE,UAAU;aACG,CAAC;QACxB,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;gBAChC,OAAO;oBACL,UAAU,EAAE,EAAE;oBACd,WAAW,EAAE,QAAQ;oBACrB,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;oBAC9D,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;oBACvB,IAAI,EAAE,UAAU;iBACG,CAAC;YACxB,CAAC;QACH,CAAC;QAED,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAK,KAA0B,EAAE,CAAC;YACjF,MAAM,aAAa,GAAI,KAA0B,CAAC,KAAK,CAAC;YACxD,OAAO;gBACL,UAAU,EAAE,EAAE;gBACd,WAAW,EAAE,QAAQ;gBACrB,QAAQ,EAAG,KAA0B,CAAC,QAAQ,IAAI,QAAQ;gBAC1D,KAAK,EAAE,aAAa,KAAK,IAAI,IAAI,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI;gBAC9F,IAAI,EAAE,UAAU;aACG,CAAC;QACxB,CAAC;QAED,OAAO;YACL,UAAU,EAAE,EAAE;YACd,WAAW,EAAE,QAAQ;YACrB,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;YACvB,IAAI,EAAE,UAAU;SACG,CAAC;IACxB,CAAC;CACF;AAtG0D;IAAxD,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC;gDAA4B;AAwGtF,cAAc,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC","sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-repeat operator generates a container by repeating an expression.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#repeat\n *\n * Attributes 'number-repeats' determines the count of iterations.\n * Returns an ordered container filled with results of the evaluated sub-expressions.\n * Special cases: Returns NULL if number-repeats < 1; ignores evaluated NULL values.\n */\nexport class QtiRepeat extends QtiExpression<ResponseVariable[]> {\n @property({ type: String, attribute: 'number-repeats' }) numberRepeats: string = '';\n\n public override getResult(): ResponseVariable[] {\n const count = this.#resolveRepeatCount();\n if (count <= 0) {\n return [];\n }\n\n const expression = this.firstElementChild as QtiExpression<unknown> | null;\n if (!expression) {\n console.warn('qti-repeat: missing child expression');\n return [];\n }\n\n const results: ResponseVariable[] = [];\n for (let i = 0; i < count; i++) {\n const value = expression.calculate();\n const variable = this.#toResponseVariable(value);\n if (variable) {\n results.push(variable);\n }\n }\n\n return results;\n }\n\n #resolveRepeatCount(): number {\n if (!this.numberRepeats) {\n console.warn('qti-repeat: missing number-repeats attribute');\n return 0;\n }\n\n const numericCount = parseInt(this.numberRepeats, 10);\n if (!Number.isNaN(numericCount)) {\n return numericCount;\n }\n\n const identifier = this.numberRepeats;\n const variable = this.context?.variables?.find(v => v.identifier === identifier);\n if (!variable) {\n console.warn(`qti-repeat: unknown identifier \"${identifier}\"`);\n return 0;\n }\n\n const rawValue = Array.isArray(variable.value) ? variable.value[0] : variable.value;\n const resolvedCount = parseInt(rawValue?.toString() ?? '', 10);\n\n if (Number.isNaN(resolvedCount)) {\n console.warn(`qti-repeat: invalid repeat count from \"${identifier}\"`);\n return 0;\n }\n\n return resolvedCount;\n }\n\n #toResponseVariable(value: unknown): ResponseVariable | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (typeof value === 'number') {\n return {\n identifier: '',\n cardinality: 'single',\n baseType: Number.isInteger(value) ? 'integer' : 'float',\n value: value.toString(),\n type: 'response'\n } as ResponseVariable;\n }\n\n if (typeof value === 'string') {\n const numericValue = parseFloat(value);\n if (!Number.isNaN(numericValue)) {\n return {\n identifier: '',\n cardinality: 'single',\n baseType: Number.isInteger(numericValue) ? 'integer' : 'float',\n value: value.toString(),\n type: 'response'\n } as ResponseVariable;\n }\n }\n\n if (value && typeof value === 'object' && 'value' in (value as ResponseVariable)) {\n const responseValue = (value as ResponseVariable).value;\n return {\n identifier: '',\n cardinality: 'single',\n baseType: (value as ResponseVariable).baseType ?? 'string',\n value: responseValue !== null && responseValue !== undefined ? responseValue.toString() : null,\n type: 'response'\n } as ResponseVariable;\n }\n\n return {\n identifier: '',\n cardinality: 'single',\n baseType: 'string',\n value: value.toString(),\n type: 'response'\n } as ResponseVariable;\n }\n}\n\ncustomElements.define('qti-repeat', QtiRepeat);\n"]}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { QtiExpression } from '@qti-components/base';
|
|
2
2
|
/**
|
|
3
3
|
* @summary The qti-round operator rounds a numerical value to the nearest integer.
|
|
4
|
-
* @documentation https://www.imsglobal.org/spec/qti/v3p0/
|
|
4
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#round
|
|
5
5
|
*
|
|
6
|
-
* Takes
|
|
7
|
-
* Returns
|
|
8
|
-
*
|
|
9
|
-
* 6.49 rounds to 6, and -6.5 rounds to -6.
|
|
6
|
+
* Takes 1 numerical sub-expression of single cardinality.
|
|
7
|
+
* Returns integer n for input in range [n-0.5, n+0.5).
|
|
8
|
+
* Special cases: Returns NULL if input is NULL or NaN.
|
|
10
9
|
*/
|
|
11
10
|
export declare class QtiRound extends QtiExpression<number | null> {
|
|
12
11
|
getResult(): number | null;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { QtiExpression } from '@qti-components/base';
|
|
2
2
|
/**
|
|
3
3
|
* @summary The qti-round operator rounds a numerical value to the nearest integer.
|
|
4
|
-
* @documentation https://www.imsglobal.org/spec/qti/v3p0/
|
|
4
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#round
|
|
5
5
|
*
|
|
6
|
-
* Takes
|
|
7
|
-
* Returns
|
|
8
|
-
*
|
|
9
|
-
* 6.49 rounds to 6, and -6.5 rounds to -6.
|
|
6
|
+
* Takes 1 numerical sub-expression of single cardinality.
|
|
7
|
+
* Returns integer n for input in range [n-0.5, n+0.5).
|
|
8
|
+
* Special cases: Returns NULL if input is NULL or NaN.
|
|
10
9
|
*/
|
|
11
10
|
export class QtiRound extends QtiExpression {
|
|
12
11
|
getResult() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qti-round.js","sourceRoot":"","sources":["../../../src/components/qti-round/qti-round.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD
|
|
1
|
+
{"version":3,"file":"qti-round.js","sourceRoot":"","sources":["../../../src/components/qti-round/qti-round.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAIrD;;;;;;;GAOG;AACH,MAAM,OAAO,QAAS,SAAQ,aAA4B;IACxC,SAAS;QACvB,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAwB,CAAC;QAC5D,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAE9B,oBAAoB;QACpB,IAAI,QAAQ,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YACtC,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,gEAAgE;QAChE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACzE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,qBAAqB;QACrB,IAAI,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kBAAkB;QAClB,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;YAC3E,OAAO,IAAI,CAAC;QACd,CAAC;QAED,oBAAoB;QACpB,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAe,CAAC,CAAC;QAE1D,uBAAuB;QACvB,IAAI,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5B,wBAAwB;YACxB,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;gBAC9B,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,IAAI,YAAY,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC/B,OAAO,CAAC,QAAQ,CAAC;YACnB,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,sFAAsF;QACtF,iEAAiE;QACjE,wCAAwC;QACxC,4BAA4B;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC;IACxC,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC","sourcesContent":["import { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-round operator rounds a numerical value to the nearest integer.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#round\n *\n * Takes 1 numerical sub-expression of single cardinality.\n * Returns integer n for input in range [n-0.5, n+0.5).\n * Special cases: Returns NULL if input is NULL or NaN.\n */\nexport class QtiRound extends QtiExpression<number | null> {\n public override getResult(): number | null {\n if (this.children.length !== 1) {\n console.error('qti-round must have exactly one child expression');\n return null;\n }\n\n const variables = this.getVariables() as ResponseVariable[];\n if (!variables || variables.length === 0) {\n return null;\n }\n\n const variable = variables[0];\n\n // Check cardinality\n if (variable.cardinality !== 'single') {\n console.error('qti-round requires single cardinality');\n return null;\n }\n\n // Check if value is array (shouldn't be for single cardinality)\n if (Array.isArray(variable.value)) {\n console.error('qti-round unexpected array value for single cardinality');\n return null;\n }\n\n // Handle null values\n if (variable.value === null || variable.value === undefined) {\n return null;\n }\n\n // Check base type\n if (variable.baseType !== 'integer' && variable.baseType !== 'float') {\n console.error('qti-round requires numerical base-type (integer or float)');\n return null;\n }\n\n // Convert to number\n const numericValue = parseFloat(variable.value as string);\n\n // Handle special cases\n if (isNaN(numericValue)) {\n console.warn('qti-round: NaN input results in NULL');\n return null;\n }\n\n if (!isFinite(numericValue)) {\n // Handle infinity cases\n if (numericValue === Infinity) {\n return Infinity;\n }\n if (numericValue === -Infinity) {\n return -Infinity;\n }\n return null;\n }\n\n // Apply QTI rounding rule: result is integer n for all input values in [n-0.5, n+0.5)\n // This means we need to find n such that: n-0.5 <= value < n+0.5\n // Rearranging: n <= value + 0.5 < n + 1\n // So n = floor(value + 0.5)\n return Math.floor(numericValue + 0.5);\n }\n}\n\ncustomElements.define('qti-round', QtiRound);\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { QtiRule } from '../qti-rule/qti-rule';
|
|
2
|
+
import type { QtiExpressionBase, QtiRuleBase } from '@qti-components/base';
|
|
3
|
+
/**
|
|
4
|
+
* Web component that processes `setCorrectResponse` in QTI.
|
|
5
|
+
*/
|
|
6
|
+
export declare class QtiSetCorrectResponse extends QtiRule {
|
|
7
|
+
#private;
|
|
8
|
+
/**
|
|
9
|
+
* Processes the QTI rule and dispatches a custom event with the computed correct response value.
|
|
10
|
+
*/
|
|
11
|
+
process(): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Encapsulates the logic for processing QTI setCorrectResponse expressions.
|
|
15
|
+
*/
|
|
16
|
+
export declare class QtiSetCorrectResponseRule<T> implements QtiRuleBase {
|
|
17
|
+
#private;
|
|
18
|
+
private expression;
|
|
19
|
+
constructor(expression: QtiExpressionBase<T>);
|
|
20
|
+
/**
|
|
21
|
+
* Evaluates the expression and returns its value.
|
|
22
|
+
*/
|
|
23
|
+
process(): unknown;
|
|
24
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { convertNumberToUniversalFormat } from '@qti-components/base';
|
|
2
|
+
import { QtiRule } from '../qti-rule/qti-rule';
|
|
3
|
+
/**
|
|
4
|
+
* Web component that processes `setCorrectResponse` in QTI.
|
|
5
|
+
*/
|
|
6
|
+
export class QtiSetCorrectResponse extends QtiRule {
|
|
7
|
+
/**
|
|
8
|
+
* Processes the QTI rule and dispatches a custom event with the computed correct response value.
|
|
9
|
+
*/
|
|
10
|
+
process() {
|
|
11
|
+
const responseIdentifier = this.getAttribute('identifier');
|
|
12
|
+
if (!responseIdentifier) {
|
|
13
|
+
console.warn('QtiSetCorrectResponse: Missing "identifier" attribute.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const expression = this.firstElementChild;
|
|
17
|
+
if (!expression) {
|
|
18
|
+
console.warn('QtiSetCorrectResponse: No expression found.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const rule = new QtiSetCorrectResponseRule(expression);
|
|
22
|
+
const value = rule.process();
|
|
23
|
+
this.dispatchEvent(new CustomEvent('qti-set-correct-response', {
|
|
24
|
+
bubbles: true,
|
|
25
|
+
composed: true,
|
|
26
|
+
detail: {
|
|
27
|
+
responseIdentifier,
|
|
28
|
+
value: this.#formatValue(value)
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
#formatValue(value) {
|
|
33
|
+
if (value === null || value === undefined) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
return value.map(item => convertNumberToUniversalFormat(this.#unwrapValue(item)));
|
|
38
|
+
}
|
|
39
|
+
return convertNumberToUniversalFormat(this.#unwrapValue(value));
|
|
40
|
+
}
|
|
41
|
+
#unwrapValue(value) {
|
|
42
|
+
if (value && typeof value === 'object' && 'value' in value) {
|
|
43
|
+
const responseValue = value.value;
|
|
44
|
+
return responseValue !== null && responseValue !== undefined ? responseValue.toString() : '';
|
|
45
|
+
}
|
|
46
|
+
return value?.toString() ?? '';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Encapsulates the logic for processing QTI setCorrectResponse expressions.
|
|
51
|
+
*/
|
|
52
|
+
export class QtiSetCorrectResponseRule {
|
|
53
|
+
constructor(expression) {
|
|
54
|
+
this.expression = expression;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Evaluates the expression and returns its value.
|
|
58
|
+
*/
|
|
59
|
+
process() {
|
|
60
|
+
const value = this.expression.calculate() ?? null;
|
|
61
|
+
if (value === null) {
|
|
62
|
+
console.warn('QtiSetCorrectResponseRule: Evaluated value is null.');
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
return value.map(item => this.#unwrapResult(item));
|
|
66
|
+
}
|
|
67
|
+
return this.#unwrapResult(value);
|
|
68
|
+
}
|
|
69
|
+
#unwrapResult(value) {
|
|
70
|
+
if (value && typeof value === 'object' && 'value' in value) {
|
|
71
|
+
return value.value;
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
customElements.define('qti-set-correct-response', QtiSetCorrectResponse);
|
|
77
|
+
//# sourceMappingURL=qti-set-correct-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qti-set-correct-response.js","sourceRoot":"","sources":["../../../src/components/qti-set-correct-response/qti-set-correct-response.ts"],"names":[],"mappings":"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","sourcesContent":["import { convertNumberToUniversalFormat } from '@qti-components/base';\n\nimport { QtiRule } from '../qti-rule/qti-rule';\n\nimport type { QtiExpression, QtiExpressionBase, QtiRuleBase, ResponseVariable } from '@qti-components/base';\n\n/**\n * Web component that processes `setCorrectResponse` in QTI.\n */\nexport class QtiSetCorrectResponse extends QtiRule {\n /**\n * Processes the QTI rule and dispatches a custom event with the computed correct response value.\n */\n public override process(): void {\n const responseIdentifier = this.getAttribute('identifier');\n\n if (!responseIdentifier) {\n console.warn('QtiSetCorrectResponse: Missing \"identifier\" attribute.');\n return;\n }\n\n const expression = this.firstElementChild as QtiExpression<unknown> | null;\n\n if (!expression) {\n console.warn('QtiSetCorrectResponse: No expression found.');\n return;\n }\n\n const rule = new QtiSetCorrectResponseRule<unknown>(expression);\n const value = rule.process();\n\n this.dispatchEvent(\n new CustomEvent<{ responseIdentifier: string; value: string | string[] | null }>('qti-set-correct-response', {\n bubbles: true,\n composed: true,\n detail: {\n responseIdentifier,\n value: this.#formatValue(value)\n }\n })\n );\n }\n\n #formatValue(value: unknown): string | string[] | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => convertNumberToUniversalFormat(this.#unwrapValue(item)));\n }\n\n return convertNumberToUniversalFormat(this.#unwrapValue(value));\n }\n\n #unwrapValue(value: unknown): string {\n if (value && typeof value === 'object' && 'value' in (value as ResponseVariable)) {\n const responseValue = (value as ResponseVariable).value;\n return responseValue !== null && responseValue !== undefined ? responseValue.toString() : '';\n }\n\n return value?.toString() ?? '';\n }\n}\n\n/**\n * Encapsulates the logic for processing QTI setCorrectResponse expressions.\n */\nexport class QtiSetCorrectResponseRule<T> implements QtiRuleBase {\n constructor(private expression: QtiExpressionBase<T>) {}\n\n /**\n * Evaluates the expression and returns its value.\n */\n process(): unknown {\n const value = this.expression.calculate() ?? null;\n\n if (value === null) {\n console.warn('QtiSetCorrectResponseRule: Evaluated value is null.');\n }\n\n if (Array.isArray(value)) {\n return value.map(item => this.#unwrapResult(item));\n }\n\n return this.#unwrapResult(value);\n }\n\n #unwrapResult(value: unknown): unknown {\n if (value && typeof value === 'object' && 'value' in (value as ResponseVariable)) {\n return (value as ResponseVariable).value;\n }\n\n return value;\n }\n}\n\ncustomElements.define('qti-set-correct-response', QtiSetCorrectResponse);\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { QtiRule } from '../qti-rule/qti-rule';
|
|
2
|
+
import type { QtiExpressionBase, QtiRuleBase } from '@qti-components/base';
|
|
3
|
+
/**
|
|
4
|
+
* Web component that processes `setTemplateValue` in QTI.
|
|
5
|
+
*/
|
|
6
|
+
export declare class QtiSetTemplateValue extends QtiRule {
|
|
7
|
+
#private;
|
|
8
|
+
/**
|
|
9
|
+
* Processes the QTI rule and dispatches a custom event with the computed template value.
|
|
10
|
+
*/
|
|
11
|
+
process(): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Encapsulates the logic for processing QTI setTemplateValue expressions.
|
|
15
|
+
*/
|
|
16
|
+
export declare class QtiSetTemplateValueRule<T> implements QtiRuleBase {
|
|
17
|
+
#private;
|
|
18
|
+
private expression;
|
|
19
|
+
constructor(expression: QtiExpressionBase<T>);
|
|
20
|
+
/**
|
|
21
|
+
* Evaluates the expression and returns its value.
|
|
22
|
+
*/
|
|
23
|
+
process(): unknown;
|
|
24
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { convertNumberToUniversalFormat } from '@qti-components/base';
|
|
2
|
+
import { QtiRule } from '../qti-rule/qti-rule';
|
|
3
|
+
/**
|
|
4
|
+
* Web component that processes `setTemplateValue` in QTI.
|
|
5
|
+
*/
|
|
6
|
+
export class QtiSetTemplateValue extends QtiRule {
|
|
7
|
+
/**
|
|
8
|
+
* Processes the QTI rule and dispatches a custom event with the computed template value.
|
|
9
|
+
*/
|
|
10
|
+
process() {
|
|
11
|
+
const templateIdentifier = this.getAttribute('identifier');
|
|
12
|
+
if (!templateIdentifier) {
|
|
13
|
+
console.warn('QtiSetTemplateValue: Missing "identifier" attribute.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const expression = this.firstElementChild;
|
|
17
|
+
if (!expression) {
|
|
18
|
+
console.warn('QtiSetTemplateValue: No expression found.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const rule = new QtiSetTemplateValueRule(expression);
|
|
22
|
+
const value = rule.process();
|
|
23
|
+
this.dispatchEvent(new CustomEvent('qti-set-template-value', {
|
|
24
|
+
bubbles: true,
|
|
25
|
+
composed: true,
|
|
26
|
+
detail: {
|
|
27
|
+
templateIdentifier,
|
|
28
|
+
value: this.#formatValue(value)
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Formats the computed value before dispatching.
|
|
34
|
+
* Ensures numbers are converted to a universal format.
|
|
35
|
+
*/
|
|
36
|
+
#formatValue(value) {
|
|
37
|
+
if (value === null || value === undefined) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
return value.map(item => convertNumberToUniversalFormat(this.#unwrapValue(item)));
|
|
42
|
+
}
|
|
43
|
+
return convertNumberToUniversalFormat(this.#unwrapValue(value));
|
|
44
|
+
}
|
|
45
|
+
#unwrapValue(value) {
|
|
46
|
+
if (value && typeof value === 'object' && 'value' in value) {
|
|
47
|
+
const responseValue = value.value;
|
|
48
|
+
return responseValue !== null && responseValue !== undefined ? responseValue.toString() : '';
|
|
49
|
+
}
|
|
50
|
+
return value?.toString() ?? '';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Encapsulates the logic for processing QTI setTemplateValue expressions.
|
|
55
|
+
*/
|
|
56
|
+
export class QtiSetTemplateValueRule {
|
|
57
|
+
constructor(expression) {
|
|
58
|
+
this.expression = expression;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Evaluates the expression and returns its value.
|
|
62
|
+
*/
|
|
63
|
+
process() {
|
|
64
|
+
const value = this.expression.calculate() ?? null;
|
|
65
|
+
if (value === null) {
|
|
66
|
+
console.warn('QtiSetTemplateValueRule: Evaluated value is null.');
|
|
67
|
+
}
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
return value.map(item => this.#unwrapResult(item));
|
|
70
|
+
}
|
|
71
|
+
return this.#unwrapResult(value);
|
|
72
|
+
}
|
|
73
|
+
#unwrapResult(value) {
|
|
74
|
+
if (value && typeof value === 'object' && 'value' in value) {
|
|
75
|
+
return value.value;
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
customElements.define('qti-set-template-value', QtiSetTemplateValue);
|
|
81
|
+
//# sourceMappingURL=qti-set-template-value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qti-set-template-value.js","sourceRoot":"","sources":["../../../src/components/qti-set-template-value/qti-set-template-value.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AAEtE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAI/C;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,OAAO;IAC9C;;OAEG;IACa,OAAO;QACrB,MAAM,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QAE3D,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAkD,CAAC;QAE3E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,uBAAuB,CAAU,UAAU,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE7B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAkE,wBAAwB,EAAE;YACzG,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,kBAAkB;gBAClB,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;aAChC;SACF,CAAC,CACH,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,YAAY,CAAC,KAAc;QACzB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,8BAA8B,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpF,CAAC;QAED,OAAO,8BAA8B,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,YAAY,CAAC,KAAc;QACzB,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAK,KAA0B,EAAE,CAAC;YACjF,MAAM,aAAa,GAAI,KAA0B,CAAC,KAAK,CAAC;YACxD,OAAO,aAAa,KAAK,IAAI,IAAI,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/F,CAAC;QAED,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,uBAAuB;IAClC,YAAoB,UAAgC;QAAhC,eAAU,GAAV,UAAU,CAAsB;IAAG,CAAC;IAExD;;OAEG;IACH,OAAO;QACL,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC;QAElD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;QACrD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,aAAa,CAAC,KAAc;QAC1B,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAK,KAA0B,EAAE,CAAC;YACjF,OAAQ,KAA0B,CAAC,KAAK,CAAC;QAC3C,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,cAAc,CAAC,MAAM,CAAC,wBAAwB,EAAE,mBAAmB,CAAC,CAAC","sourcesContent":["import { convertNumberToUniversalFormat } from '@qti-components/base';\n\nimport { QtiRule } from '../qti-rule/qti-rule';\n\nimport type { QtiExpression, QtiExpressionBase, QtiRuleBase, ResponseVariable } from '@qti-components/base';\n\n/**\n * Web component that processes `setTemplateValue` in QTI.\n */\nexport class QtiSetTemplateValue extends QtiRule {\n /**\n * Processes the QTI rule and dispatches a custom event with the computed template value.\n */\n public override process(): void {\n const templateIdentifier = this.getAttribute('identifier');\n\n if (!templateIdentifier) {\n console.warn('QtiSetTemplateValue: Missing \"identifier\" attribute.');\n return;\n }\n\n const expression = this.firstElementChild as QtiExpression<unknown> | null;\n\n if (!expression) {\n console.warn('QtiSetTemplateValue: No expression found.');\n return;\n }\n\n const rule = new QtiSetTemplateValueRule<unknown>(expression);\n const value = rule.process();\n\n this.dispatchEvent(\n new CustomEvent<{ templateIdentifier: string; value: string | string[] | null }>('qti-set-template-value', {\n bubbles: true,\n composed: true,\n detail: {\n templateIdentifier,\n value: this.#formatValue(value)\n }\n })\n );\n }\n\n /**\n * Formats the computed value before dispatching.\n * Ensures numbers are converted to a universal format.\n */\n #formatValue(value: unknown): string | string[] | null {\n if (value === null || value === undefined) {\n return null;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => convertNumberToUniversalFormat(this.#unwrapValue(item)));\n }\n\n return convertNumberToUniversalFormat(this.#unwrapValue(value));\n }\n\n #unwrapValue(value: unknown): string {\n if (value && typeof value === 'object' && 'value' in (value as ResponseVariable)) {\n const responseValue = (value as ResponseVariable).value;\n return responseValue !== null && responseValue !== undefined ? responseValue.toString() : '';\n }\n\n return value?.toString() ?? '';\n }\n}\n\n/**\n * Encapsulates the logic for processing QTI setTemplateValue expressions.\n */\nexport class QtiSetTemplateValueRule<T> implements QtiRuleBase {\n constructor(private expression: QtiExpressionBase<T>) {}\n\n /**\n * Evaluates the expression and returns its value.\n */\n process(): unknown {\n const value = this.expression.calculate() ?? null;\n\n if (value === null) {\n console.warn('QtiSetTemplateValueRule: Evaluated value is null.');\n }\n\n if (Array.isArray(value)) {\n return value.map(item => this.#unwrapResult(item));\n }\n\n return this.#unwrapResult(value);\n }\n\n #unwrapResult(value: unknown): unknown {\n if (value && typeof value === 'object' && 'value' in (value as ResponseVariable)) {\n return (value as ResponseVariable).value;\n }\n\n return value;\n }\n}\n\ncustomElements.define('qti-set-template-value', QtiSetTemplateValue);\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { QtiExpression } from '@qti-components/base';
|
|
2
|
+
/**
|
|
3
|
+
* @summary The qti-stats-operator performs statistical calculations on a container.
|
|
4
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#statsOperator
|
|
5
|
+
*
|
|
6
|
+
* Takes 1 container (multiple/ordered) of numerical base-type.
|
|
7
|
+
* 'name' attribute identifies function (mean, popSD, popVariance, sampleSD, sampleVariance).
|
|
8
|
+
* Returns result as a single float.
|
|
9
|
+
* Special cases: Returns NULL if any values in container are NULL or non-numerical.
|
|
10
|
+
*/
|
|
11
|
+
export declare class QtiStatsOperator extends QtiExpression<number | null> {
|
|
12
|
+
#private;
|
|
13
|
+
name: string;
|
|
14
|
+
getResult(): number | null;
|
|
15
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { property } from 'lit/decorators.js';
|
|
8
|
+
import { QtiExpression } from '@qti-components/base';
|
|
9
|
+
/**
|
|
10
|
+
* @summary The qti-stats-operator performs statistical calculations on a container.
|
|
11
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#statsOperator
|
|
12
|
+
*
|
|
13
|
+
* Takes 1 container (multiple/ordered) of numerical base-type.
|
|
14
|
+
* 'name' attribute identifies function (mean, popSD, popVariance, sampleSD, sampleVariance).
|
|
15
|
+
* Returns result as a single float.
|
|
16
|
+
* Special cases: Returns NULL if any values in container are NULL or non-numerical.
|
|
17
|
+
*/
|
|
18
|
+
export class QtiStatsOperator extends QtiExpression {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this.name = '';
|
|
22
|
+
}
|
|
23
|
+
getResult() {
|
|
24
|
+
if (!this.name) {
|
|
25
|
+
console.warn('qti-stats-operator: missing name attribute');
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const values = this.#collectNumericValues(this.getVariables());
|
|
29
|
+
if (values.length === 0) {
|
|
30
|
+
console.warn('qti-stats-operator: no numeric values provided');
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
switch (this.name.toLowerCase()) {
|
|
34
|
+
case 'mean':
|
|
35
|
+
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
36
|
+
case 'popsd':
|
|
37
|
+
return this.#populationStandardDeviation(values);
|
|
38
|
+
default:
|
|
39
|
+
console.warn(`qti-stats-operator: unsupported operator "${this.name}"`);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
#populationStandardDeviation(values) {
|
|
44
|
+
const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
45
|
+
const variance = values.reduce((sum, value) => sum + Math.pow(value - mean, 2), 0) / values.length;
|
|
46
|
+
return Math.sqrt(variance);
|
|
47
|
+
}
|
|
48
|
+
#collectNumericValues(variables) {
|
|
49
|
+
const values = [];
|
|
50
|
+
for (const variable of variables) {
|
|
51
|
+
if (!variable) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const pushValue = (raw) => {
|
|
55
|
+
if (raw === null || raw === undefined) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const numValue = parseFloat(raw.toString());
|
|
59
|
+
if (Number.isNaN(numValue)) {
|
|
60
|
+
console.warn('qti-stats-operator: non-numeric value encountered');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
values.push(numValue);
|
|
64
|
+
};
|
|
65
|
+
if (Array.isArray(variable.value)) {
|
|
66
|
+
variable.value.forEach(item => pushValue(item));
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
pushValue(variable.value);
|
|
70
|
+
}
|
|
71
|
+
return values;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
__decorate([
|
|
75
|
+
property({ type: String })
|
|
76
|
+
], QtiStatsOperator.prototype, "name", void 0);
|
|
77
|
+
customElements.define('qti-stats-operator', QtiStatsOperator);
|
|
78
|
+
//# sourceMappingURL=qti-stats-operator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qti-stats-operator.js","sourceRoot":"","sources":["../../../src/components/qti-stats-operator/qti-stats-operator.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\n\nimport { QtiExpression } from '@qti-components/base';\n\nimport type { ResponseVariable } from '@qti-components/base';\n\n/**\n * @summary The qti-stats-operator performs statistical calculations on a container.\n * @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#statsOperator\n *\n * Takes 1 container (multiple/ordered) of numerical base-type.\n * 'name' attribute identifies function (mean, popSD, popVariance, sampleSD, sampleVariance).\n * Returns result as a single float.\n * Special cases: Returns NULL if any values in container are NULL or non-numerical.\n */\nexport class QtiStatsOperator extends QtiExpression<number | null> {\n @property({ type: String }) name: string = '';\n\n public override getResult(): number | null {\n if (!this.name) {\n console.warn('qti-stats-operator: missing name attribute');\n return null;\n }\n\n const values = this.#collectNumericValues(this.getVariables() as ResponseVariable[]);\n if (values.length === 0) {\n console.warn('qti-stats-operator: no numeric values provided');\n return null;\n }\n\n switch (this.name.toLowerCase()) {\n case 'mean':\n return values.reduce((sum, value) => sum + value, 0) / values.length;\n case 'popsd':\n return this.#populationStandardDeviation(values);\n default:\n console.warn(`qti-stats-operator: unsupported operator \"${this.name}\"`);\n return null;\n }\n }\n\n #populationStandardDeviation(values: number[]): number {\n const mean = values.reduce((sum, value) => sum + value, 0) / values.length;\n const variance = values.reduce((sum, value) => sum + Math.pow(value - mean, 2), 0) / values.length;\n return Math.sqrt(variance);\n }\n\n #collectNumericValues(variables: ResponseVariable[]): number[] {\n const values: number[] = [];\n\n for (const variable of variables) {\n if (!variable) {\n continue;\n }\n\n const pushValue = (raw: unknown) => {\n if (raw === null || raw === undefined) {\n return;\n }\n const numValue = parseFloat(raw.toString());\n if (Number.isNaN(numValue)) {\n console.warn('qti-stats-operator: non-numeric value encountered');\n return;\n }\n values.push(numValue);\n };\n\n if (Array.isArray(variable.value)) {\n variable.value.forEach(item => pushValue(item));\n continue;\n }\n\n pushValue(variable.value);\n }\n\n return values;\n }\n}\n\ncustomElements.define('qti-stats-operator', QtiStatsOperator);\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { QtiExpression } from '@qti-components/base';
|
|
2
|
+
/**
|
|
3
|
+
* @summary The qti-substring operator checks if one string is contained within another.
|
|
4
|
+
* @documentation https://www.imsglobal.org/spec/qti/v3p0/info/index.html#substring
|
|
5
|
+
*
|
|
6
|
+
* Takes 2 sub-expressions with base-type string and single cardinality.
|
|
7
|
+
* Returns true if the first string is a substring of the second.
|
|
8
|
+
* Special cases: Returns NULL if either argument is NULL.
|
|
9
|
+
*/
|
|
10
|
+
export declare class QtiSubstring extends QtiExpression<boolean | null> {
|
|
11
|
+
caseSensitive: string;
|
|
12
|
+
getResult(): boolean | null;
|
|
13
|
+
}
|