@khanacademy/perseus-core 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { seededRNG as seededRNG$1, shuffle as shuffle$2 } from '@khanacademy/perseus-core';
2
+
1
3
  /**
2
4
  * Adds the given perseus library version information to the __perseus_debug__
3
5
  * object and ensures that the object is attached to `globalThis` (`window` in
@@ -818,7 +820,7 @@ function times(n, iteratee, context) {
818
820
  }
819
821
 
820
822
  // Return a random integer between `min` and `max` (inclusive).
821
- function random(min, max) {
823
+ function random$1(min, max) {
822
824
  if (max == null) {
823
825
  max = min;
824
826
  min = 0;
@@ -1561,14 +1563,14 @@ function toArray(obj) {
1561
1563
  function sample(obj, n, guard) {
1562
1564
  if (n == null || guard) {
1563
1565
  if (!isArrayLike(obj)) obj = values(obj);
1564
- return obj[random(obj.length - 1)];
1566
+ return obj[random$1(obj.length - 1)];
1565
1567
  }
1566
1568
  var sample = toArray(obj);
1567
1569
  var length = getLength(sample);
1568
1570
  n = Math.max(Math.min(n, length), 0);
1569
1571
  var last = length - 1;
1570
1572
  for (var index = 0; index < n; index++) {
1571
- var rand = random(index, last);
1573
+ var rand = random$1(index, last);
1572
1574
  var temp = sample[index];
1573
1575
  sample[index] = sample[rand];
1574
1576
  sample[rand] = temp;
@@ -1577,7 +1579,7 @@ function sample(obj, n, guard) {
1577
1579
  }
1578
1580
 
1579
1581
  // Shuffle a collection.
1580
- function shuffle(obj) {
1582
+ function shuffle$1(obj) {
1581
1583
  return sample(obj, Infinity);
1582
1584
  }
1583
1585
 
@@ -1963,7 +1965,7 @@ var allExports = /*#__PURE__*/Object.freeze({
1963
1965
  matcher: matcher,
1964
1966
  matches: matcher,
1965
1967
  times: times,
1966
- random: random,
1968
+ random: random$1,
1967
1969
  now: now,
1968
1970
  escape: escape,
1969
1971
  unescape: unescape,
@@ -2020,7 +2022,7 @@ var allExports = /*#__PURE__*/Object.freeze({
2020
2022
  where: where,
2021
2023
  max: max,
2022
2024
  min: min,
2023
- shuffle: shuffle,
2025
+ shuffle: shuffle$1,
2024
2026
  sample: sample,
2025
2027
  sortBy: sortBy,
2026
2028
  groupBy: groupBy,
@@ -3076,7 +3078,7 @@ function parseWidget(parseType, parseOptions) {
3076
3078
  graded: optional(boolean),
3077
3079
  alignment: optional(string),
3078
3080
  options: parseOptions,
3079
- key: optional(number),
3081
+ key: optional(nullable(number)),
3080
3082
  version: optional(object({
3081
3083
  major: number,
3082
3084
  minor: number
@@ -3156,6 +3158,13 @@ function convert(f) {
3156
3158
  return (rawValue, ctx) => ctx.success(f(rawValue));
3157
3159
  }
3158
3160
 
3161
+ const parseLegacyButtonSet = enumeration("basic", "basic+div", "trig", "prealgebra", "logarithms", "basic relations", "advanced relations", "scientific");
3162
+ const parseLegacyButtonSets = defaulted(array(parseLegacyButtonSet),
3163
+ // NOTE(benchristel): I copied the default buttonSets from
3164
+ // expression.tsx. See the parse-perseus-json/README.md for
3165
+ // an explanation of why we want to duplicate the default here.
3166
+ () => ["basic", "trig", "prealgebra", "logarithms"]);
3167
+
3159
3168
  /**
3160
3169
  * Creates a parser for a widget options type with multiple major versions. Old
3161
3170
  * versions are migrated to the latest version. The parse fails if the input
@@ -3244,11 +3253,6 @@ function removeInvalidAnswerForms(possiblyInvalid) {
3244
3253
  }
3245
3254
  return valid;
3246
3255
  }
3247
-
3248
- // NOTE(benchristel): I copied the default buttonSets from
3249
- // expression.tsx. See the parse-perseus-json/README.md for
3250
- // an explanation of why we want to duplicate the default here.
3251
- const parseButtonSets = defaulted(array(enumeration("basic", "basic+div", "trig", "prealgebra", "logarithms", "basic relations", "advanced relations")), () => ["basic", "trig", "prealgebra", "logarithms"]);
3252
3256
  const version1 = object({
3253
3257
  major: constant(1),
3254
3258
  minor: number
@@ -3259,7 +3263,7 @@ const parseExpressionWidgetV1 = parseWidgetWithVersion(version1, constant("expre
3259
3263
  times: boolean,
3260
3264
  visibleLabel: optional(string),
3261
3265
  ariaLabel: optional(string),
3262
- buttonSets: parseButtonSets,
3266
+ buttonSets: parseLegacyButtonSets,
3263
3267
  buttonsVisible: optional(enumeration("always", "never", "focused"))
3264
3268
  }));
3265
3269
  const version0 = optional(object({
@@ -3274,7 +3278,7 @@ const parseExpressionWidgetV0 = parseWidgetWithVersion(version0, constant("expre
3274
3278
  form: boolean,
3275
3279
  simplify: boolean,
3276
3280
  value: string,
3277
- buttonSets: parseButtonSets,
3281
+ buttonSets: parseLegacyButtonSets,
3278
3282
  buttonsVisible: optional(enumeration("always", "never", "focused"))
3279
3283
  }));
3280
3284
  function migrateV0ToV1(widget) {
@@ -3460,14 +3464,15 @@ const imageDimensionToNumber = pipeParsers(union(number).or(string).parser)
3460
3464
  // string parses to either NaN (using parseInt) or 0 (using unary +) and
3461
3465
  // CSS will treat NaN as invalid and default to 0 instead.
3462
3466
  .then(convert(emptyToZero)).then(stringToNumber).parser;
3467
+ const dimensionOrUndefined = defaulted(imageDimensionToNumber, () => undefined);
3463
3468
  const parsePerseusImageBackground = object({
3464
3469
  url: optional(nullable(string)),
3465
- width: optional(imageDimensionToNumber),
3466
- height: optional(imageDimensionToNumber),
3467
- top: optional(imageDimensionToNumber),
3468
- left: optional(imageDimensionToNumber),
3469
- bottom: optional(imageDimensionToNumber),
3470
- scale: optional(imageDimensionToNumber)
3470
+ width: dimensionOrUndefined,
3471
+ height: dimensionOrUndefined,
3472
+ top: dimensionOrUndefined,
3473
+ left: dimensionOrUndefined,
3474
+ bottom: dimensionOrUndefined,
3475
+ scale: dimensionOrUndefined
3471
3476
  });
3472
3477
 
3473
3478
  const pairOfNumbers$2 = pair(number, number);
@@ -4208,7 +4213,7 @@ const parseNumericInputWidget = parseWidget(constant("numeric-input"), object({
4208
4213
  // the data, simplify this.
4209
4214
  value: optional(nullable(number)),
4210
4215
  status: string,
4211
- answerForms: optional(array(parseMathFormat)),
4216
+ answerForms: defaulted(array(parseMathFormat), () => undefined),
4212
4217
  strict: boolean,
4213
4218
  maxError: optional(nullable(number)),
4214
4219
  // TODO(benchristel): simplify should never be a boolean, but we
@@ -4306,7 +4311,7 @@ const parseRadioWidget = parseWidget(constant("radio"), object({
4306
4311
  // There is an import cycle between radio-widget.ts and
4307
4312
  // widgets-map.ts. The anonymous function below ensures that we
4308
4313
  // don't refer to parseWidgetsMap before it's defined.
4309
- widgets: optional((rawVal, ctx) => parseWidgetsMap(rawVal, ctx))
4314
+ widgets: defaulted((rawVal, ctx) => parseWidgetsMap(rawVal, ctx), () => undefined)
4310
4315
  })),
4311
4316
  hasNoneOfTheAbove: optional(boolean),
4312
4317
  countChoices: optional(boolean),
@@ -4459,13 +4464,17 @@ const parseDeprecatedWidget = parseWidget(
4459
4464
  (_, ctx) => ctx.success("deprecated-standin"),
4460
4465
  // Allow any widget options
4461
4466
  object({}));
4462
- const parseStringToPositiveInt = (rawValue, ctx) => {
4463
- if (typeof rawValue !== "string" || !/^[1-9][0-9]*$/.test(rawValue)) {
4464
- return ctx.failure("a string representing a positive integer", rawValue);
4467
+ const parseStringToNonNegativeInt = (rawValue, ctx) => {
4468
+ // The article renderer seems to allow the numeric part of a widget ID to
4469
+ // be 0, at least for image widgets. However, if widget IDs in an exercise
4470
+ // contain 0, the exercise renderer will blow up. We allow 0 here for
4471
+ // compatibility with articles.
4472
+ if (typeof rawValue !== "string" || !/^(0|[1-9][0-9]*)$/.test(rawValue)) {
4473
+ return ctx.failure("a string representing a non-negative integer", rawValue);
4465
4474
  }
4466
4475
  return ctx.success(+rawValue);
4467
4476
  };
4468
- const parseWidgetIdComponents = pair(string, parseStringToPositiveInt);
4477
+ const parseWidgetIdComponents = pair(string, parseStringToNonNegativeInt);
4469
4478
 
4470
4479
  const parsePerseusRenderer = defaulted(object({
4471
4480
  // TODO(benchristel): content is also defaulted to empty string in
@@ -4476,8 +4485,9 @@ const parsePerseusRenderer = defaulted(object({
4476
4485
  // The anonymous function below ensures that we don't try to access
4477
4486
  // parseWidgetsMap before it's defined.
4478
4487
  widgets: defaulted((rawVal, ctx) => parseWidgetsMap(rawVal, ctx), () => ({})),
4479
- metadata: optional(array(string)),
4480
- images: parseImages
4488
+ images: parseImages,
4489
+ // deprecated
4490
+ metadata: any
4481
4491
  }),
4482
4492
  // Default value
4483
4493
  () => ({
@@ -4488,29 +4498,48 @@ const parsePerseusRenderer = defaulted(object({
4488
4498
 
4489
4499
  const parsePerseusArticle = union(parsePerseusRenderer).or(array(parsePerseusRenderer)).parser;
4490
4500
 
4491
- function _objectWithoutPropertiesLoose(r, e) {
4492
- if (null == r) return {};
4493
- var t = {};
4494
- for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
4495
- if (-1 !== e.indexOf(n)) continue;
4496
- t[n] = r[n];
4497
- }
4498
- return t;
4499
- }
4500
-
4501
4501
  const parseHint = object({
4502
4502
  replace: optional(boolean),
4503
4503
  content: string,
4504
4504
  widgets: defaulted(parseWidgetsMap, () => ({})),
4505
- metadata: optional(array(string)),
4506
- images: parseImages
4505
+ images: parseImages,
4506
+ // deprecated
4507
+ metadata: any
4507
4508
  });
4508
4509
 
4509
- const _excluded$a = ["type", "options"];
4510
+ const parsePerseusAnswerArea = pipeParsers(defaulted(object({}), () => ({}))).then(convert(toAnswerArea)).parser;
4511
+
4512
+ // Some answerAreas have extra, bogus fields, like:
4513
+ //
4514
+ // "answerArea": {
4515
+ // "type": "multiple",
4516
+ // "options": {},
4517
+ // "version": null,
4518
+ // "static": false,
4519
+ // "graded": false,
4520
+ // "alignment": "",
4521
+ // }
4522
+ //
4523
+ // This function filters the fields of an answerArea object, keeping only the
4524
+ // known ones, and converts `undefined` and `null` values to `false`.
4525
+ function toAnswerArea(raw) {
4526
+ return {
4527
+ zTable: !!raw.zTable,
4528
+ calculator: !!raw.calculator,
4529
+ chi2Table: !!raw.chi2Table,
4530
+ financialCalculatorMonthlyPayment: !!raw.financialCalculatorMonthlyPayment,
4531
+ financialCalculatorTotalAmount: !!raw.financialCalculatorTotalAmount,
4532
+ financialCalculatorTimeToPayOff: !!raw.financialCalculatorTimeToPayOff,
4533
+ periodicTable: !!raw.periodicTable,
4534
+ periodicTableWithKey: !!raw.periodicTableWithKey,
4535
+ tTable: !!raw.tTable
4536
+ };
4537
+ }
4538
+
4510
4539
  const parsePerseusItem$1 = object({
4511
4540
  question: parsePerseusRenderer,
4512
4541
  hints: defaulted(array(parseHint), () => []),
4513
- answerArea: pipeParsers(defaulted(object({}), () => ({}))).then(migrateAnswerArea).then(record(enumeration(...ItemExtras), boolean)).parser,
4542
+ answerArea: parsePerseusAnswerArea,
4514
4543
  itemDataVersion: optional(object({
4515
4544
  major: number,
4516
4545
  minor: number
@@ -4519,24 +4548,6 @@ const parsePerseusItem$1 = object({
4519
4548
  answer: any
4520
4549
  });
4521
4550
 
4522
- // Some answerAreas have extra fields, like:
4523
- //
4524
- // "answerArea": {
4525
- // "type": "multiple",
4526
- // "options": {
4527
- // "content": "",
4528
- // "images": {},
4529
- // "widgets": {}
4530
- // }
4531
- // }
4532
- //
4533
- // The "type" and "options" fields don't seem to be used anywhere. This
4534
- // migration function removes them.
4535
- function migrateAnswerArea(rawValue, ctx) {
4536
- const rest = _objectWithoutPropertiesLoose(rawValue, _excluded$a);
4537
- return ctx.success(rest);
4538
- }
4539
-
4540
4551
  /**
4541
4552
  * Helper to parse PerseusItem JSON
4542
4553
  * Why not just use JSON.parse? We want:
@@ -4611,7 +4622,7 @@ function throwErrorIfCheatingDetected() {
4611
4622
 
4612
4623
  // This file is processed by a Rollup plugin (replace) to inject the production
4613
4624
  const libName = "@khanacademy/perseus-core";
4614
- const libVersion = "3.5.0";
4625
+ const libVersion = "3.7.0";
4615
4626
  addLibraryVersionToPerseusDebug(libName, libVersion);
4616
4627
 
4617
4628
  /**
@@ -4710,6 +4721,24 @@ const mapObject = function mapObject(obj, lambda) {
4710
4721
  return result;
4711
4722
  };
4712
4723
 
4724
+ /**
4725
+ * For details on the individual options, see the
4726
+ * PerseusCategorizerWidgetOptions type
4727
+ */
4728
+
4729
+ /**
4730
+ * Given a PerseusCategorizerWidgetOptions object, return a new object with only
4731
+ * the public options that should be exposed to the client.
4732
+ */
4733
+ function getCategorizerPublicWidgetOptions(options) {
4734
+ return {
4735
+ items: options.items,
4736
+ categories: options.categories,
4737
+ randomizeItems: options.randomizeItems,
4738
+ static: options.static
4739
+ };
4740
+ }
4741
+
4713
4742
  const defaultWidgetOptions$v = {
4714
4743
  items: [],
4715
4744
  categories: [],
@@ -4718,9 +4747,14 @@ const defaultWidgetOptions$v = {
4718
4747
  };
4719
4748
  const categorizerWidgetLogic = {
4720
4749
  name: "categorizer",
4721
- defaultWidgetOptions: defaultWidgetOptions$v
4750
+ defaultWidgetOptions: defaultWidgetOptions$v,
4751
+ getPublicWidgetOptions: getCategorizerPublicWidgetOptions
4722
4752
  };
4723
4753
 
4754
+ function getCSProgramPublicWidgetOptions(options) {
4755
+ return options;
4756
+ }
4757
+
4724
4758
  const DEFAULT_HEIGHT = 400;
4725
4759
  const defaultWidgetOptions$u = {
4726
4760
  programID: "",
@@ -4736,7 +4770,8 @@ const defaultWidgetOptions$u = {
4736
4770
  const csProgramWidgetLogic = {
4737
4771
  name: "cs-program",
4738
4772
  defaultWidgetOptions: defaultWidgetOptions$u,
4739
- supportedAlignments: ["block", "full-width"]
4773
+ supportedAlignments: ["block", "full-width"],
4774
+ getPublicWidgetOptions: getCSProgramPublicWidgetOptions
4740
4775
  };
4741
4776
 
4742
4777
  const defaultWidgetOptions$t = {
@@ -4749,6 +4784,27 @@ const definitionWidgetLogic = {
4749
4784
  defaultAlignment: "inline"
4750
4785
  };
4751
4786
 
4787
+ /**
4788
+ * For details on the individual options, see the
4789
+ * PerseusDropdownWidgetOptions type
4790
+ */
4791
+
4792
+ /**
4793
+ * Given a PerseusDropdownWidgetOptions object, return a new object with only
4794
+ * the public options that should be exposed to the client.
4795
+ */
4796
+ function getDropdownPublicWidgetOptions(options) {
4797
+ return {
4798
+ choices: options.choices.map(choice => ({
4799
+ content: choice.content
4800
+ })),
4801
+ placeholder: options.placeholder,
4802
+ static: options.static,
4803
+ visibleLabel: options.visibleLabel,
4804
+ ariaLabel: options.ariaLabel
4805
+ };
4806
+ }
4807
+
4752
4808
  const defaultWidgetOptions$s = {
4753
4809
  placeholder: "",
4754
4810
  choices: [{
@@ -4759,7 +4815,8 @@ const defaultWidgetOptions$s = {
4759
4815
  const dropdownWidgetLogic = {
4760
4816
  name: "definition",
4761
4817
  defaultWidgetOptions: defaultWidgetOptions$s,
4762
- defaultAlignment: "inline-block"
4818
+ defaultAlignment: "inline-block",
4819
+ getPublicWidgetOptions: getDropdownPublicWidgetOptions
4763
4820
  };
4764
4821
 
4765
4822
  const defaultWidgetOptions$r = {
@@ -4801,12 +4858,33 @@ const defaultWidgetOptions$q = {
4801
4858
  functions: ["f", "g", "h"]
4802
4859
  };
4803
4860
 
4861
+ /**
4862
+ * For details on the individual options, see the
4863
+ * PerseusExpressionWidgetOptions type
4864
+ */
4865
+
4866
+ /**
4867
+ * Given a PerseusExpressionWidgetOptions object, return a new object with only
4868
+ * the public options that should be exposed to the client.
4869
+ */
4870
+ function getExpressionPublicWidgetOptions(options) {
4871
+ return {
4872
+ buttonSets: options.buttonSets,
4873
+ functions: options.functions,
4874
+ times: options.times,
4875
+ visibleLabel: options.visibleLabel,
4876
+ ariaLabel: options.ariaLabel,
4877
+ buttonsVisible: options.buttonsVisible
4878
+ };
4879
+ }
4880
+
4804
4881
  const expressionWidgetLogic = {
4805
4882
  name: "expression",
4806
4883
  version: currentVersion$3,
4807
4884
  widgetOptionsUpgrades: widgetOptionsUpgrades$2,
4808
4885
  defaultWidgetOptions: defaultWidgetOptions$q,
4809
- defaultAlignment: "inline-block"
4886
+ defaultAlignment: "inline-block",
4887
+ getPublicWidgetOptions: getExpressionPublicWidgetOptions
4810
4888
  };
4811
4889
 
4812
4890
  const defaultWidgetOptions$p = {
@@ -4829,6 +4907,22 @@ const gradedGroupSetWidgetLogic = {
4829
4907
  defaultWidgetOptions: defaultWidgetOptions$o
4830
4908
  };
4831
4909
 
4910
+ function _objectWithoutPropertiesLoose(r, e) {
4911
+ if (null == r) return {};
4912
+ var t = {};
4913
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
4914
+ if (-1 !== e.indexOf(n)) continue;
4915
+ t[n] = r[n];
4916
+ }
4917
+ return t;
4918
+ }
4919
+
4920
+ const _excluded$9 = ["correct"];
4921
+ function getGrapherPublicWidgetOptions(options) {
4922
+ const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$9);
4923
+ return publicOptions;
4924
+ }
4925
+
4832
4926
  const defaultWidgetOptions$n = {
4833
4927
  graph: {
4834
4928
  labels: ["x", "y"],
@@ -4851,22 +4945,24 @@ const defaultWidgetOptions$n = {
4851
4945
  };
4852
4946
  const grapherWidgetLogic = {
4853
4947
  name: "grapher",
4854
- defaultWidgetOptions: defaultWidgetOptions$n
4948
+ defaultWidgetOptions: defaultWidgetOptions$n,
4949
+ getPublicWidgetOptions: getGrapherPublicWidgetOptions
4855
4950
  };
4856
4951
 
4857
4952
  const defaultWidgetOptions$m = {
4858
4953
  content: "",
4859
4954
  widgets: {},
4860
- images: {},
4861
- // `undefined` instead of `null` so that getDefaultProps works for
4862
- // `the GroupMetadataEditor`
4863
- metadata: undefined
4955
+ images: {}
4864
4956
  };
4865
4957
  const groupWidgetLogic = {
4866
4958
  name: "group",
4867
4959
  defaultWidgetOptions: defaultWidgetOptions$m
4868
4960
  };
4869
4961
 
4962
+ function getIFramePublicWidgetOptions(options) {
4963
+ return options;
4964
+ }
4965
+
4870
4966
  const defaultWidgetOptions$l = {
4871
4967
  url: "",
4872
4968
  settings: [{
@@ -4880,7 +4976,8 @@ const defaultWidgetOptions$l = {
4880
4976
  };
4881
4977
  const iframeWidgetLogic = {
4882
4978
  name: "iframe",
4883
- defaultWidgetOptions: defaultWidgetOptions$l
4979
+ defaultWidgetOptions: defaultWidgetOptions$l,
4980
+ getPublicWidgetOptions: getIFramePublicWidgetOptions
4884
4981
  };
4885
4982
 
4886
4983
  const defaultWidgetOptions$k = {
@@ -4934,6 +5031,12 @@ const interactionWidgetLogic = {
4934
5031
  defaultWidgetOptions: defaultWidgetOptions$i
4935
5032
  };
4936
5033
 
5034
+ const _excluded$8 = ["correct"];
5035
+ function getInteractiveGraphPublicWidgetOptions(options) {
5036
+ const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$8);
5037
+ return publicOptions;
5038
+ }
5039
+
4937
5040
  const defaultWidgetOptions$h = {
4938
5041
  labels: ["x", "y"],
4939
5042
  range: [[-10, 10], [-10, 10]],
@@ -4954,9 +5057,26 @@ const defaultWidgetOptions$h = {
4954
5057
  };
4955
5058
  const interactiveGraphWidgetLogic = {
4956
5059
  name: "interactive-graph",
4957
- defaultWidgetOptions: defaultWidgetOptions$h
5060
+ defaultWidgetOptions: defaultWidgetOptions$h,
5061
+ getPublicWidgetOptions: getInteractiveGraphPublicWidgetOptions
4958
5062
  };
4959
5063
 
5064
+ const _excluded$7 = ["answers"];
5065
+ /**
5066
+ * For details on the individual options, see the
5067
+ * PerseusLabelImageWidgetOptions type
5068
+ */
5069
+
5070
+ function getLabelImagePublicWidgetOptions(options) {
5071
+ return _extends({}, options, {
5072
+ markers: options.markers.map(getLabelImageMarkerPublicData)
5073
+ });
5074
+ }
5075
+ function getLabelImageMarkerPublicData(marker) {
5076
+ const publicData = _objectWithoutPropertiesLoose(marker, _excluded$7);
5077
+ return publicData;
5078
+ }
5079
+
4960
5080
  const defaultWidgetOptions$g = {
4961
5081
  choices: [],
4962
5082
  imageAlt: "",
@@ -4969,9 +5089,67 @@ const defaultWidgetOptions$g = {
4969
5089
  };
4970
5090
  const labelImageWidgetLogic = {
4971
5091
  name: "label-image",
4972
- defaultWidgetOptions: defaultWidgetOptions$g
5092
+ defaultWidgetOptions: defaultWidgetOptions$g,
5093
+ getPublicWidgetOptions: getLabelImagePublicWidgetOptions
4973
5094
  };
4974
5095
 
5096
+ // TODO(LEMS-2841): Should be able to remove once getPublicWidgetOptions is hooked up
5097
+
5098
+ // TODO(LEMS-2841): Should be able to remove once getPublicWidgetOptions is hooked up
5099
+ const shuffleMatcher = props => {
5100
+ // Use the same random() function to shuffle both columns sequentially
5101
+ const rng = seededRNG$1(props.problemNum);
5102
+ let left;
5103
+ if (!props.orderMatters) {
5104
+ // If the order doesn't matter, don't shuffle the left column
5105
+ left = props.left;
5106
+ } else {
5107
+ left = shuffle$2(props.left, rng, /* ensurePermuted */true);
5108
+ }
5109
+ const right = shuffle$2(props.right, rng, /* ensurePermuted */true);
5110
+ return {
5111
+ left,
5112
+ right
5113
+ };
5114
+ };
5115
+
5116
+ // TODO(LEMS-2841): Can shorten to shuffleMatcher after above function removed
5117
+ function shuffleMatcherWithRandom(data) {
5118
+ // Use the same random() function to shuffle both columns sequentially
5119
+ let left;
5120
+ if (!data.orderMatters) {
5121
+ // If the order doesn't matter, don't shuffle the left column
5122
+ left = data.left;
5123
+ } else {
5124
+ left = shuffle$2(data.left, Math.random, /* ensurePermuted */true);
5125
+ }
5126
+ const right = shuffle$2(data.right, Math.random, /* ensurePermuted */true);
5127
+ return {
5128
+ left,
5129
+ right
5130
+ };
5131
+ }
5132
+
5133
+ /**
5134
+ * For details on the individual options, see the
5135
+ * PerseusMatcherWidgetOptions type
5136
+ */
5137
+
5138
+ /**
5139
+ * Given a PerseusMatcherWidgetOptions object, return a new object with only
5140
+ * the public options that should be exposed to the client.
5141
+ */
5142
+ function getMatcherPublicWidgetOptions(options) {
5143
+ const {
5144
+ left,
5145
+ right
5146
+ } = shuffleMatcherWithRandom(options);
5147
+ return _extends({}, options, {
5148
+ left: left,
5149
+ right: right
5150
+ });
5151
+ }
5152
+
4975
5153
  const defaultWidgetOptions$f = {
4976
5154
  left: ["$x$", "$y$", "$z$"],
4977
5155
  right: ["$1$", "$2$", "$3$"],
@@ -4981,9 +5159,16 @@ const defaultWidgetOptions$f = {
4981
5159
  };
4982
5160
  const matcherWidgetLogic = {
4983
5161
  name: "matcher",
4984
- defaultWidgetOptions: defaultWidgetOptions$f
5162
+ defaultWidgetOptions: defaultWidgetOptions$f,
5163
+ getPublicWidgetOptions: getMatcherPublicWidgetOptions
4985
5164
  };
4986
5165
 
5166
+ const _excluded$6 = ["answers"];
5167
+ function getMatrixPublicWidgetOptions(options) {
5168
+ const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$6);
5169
+ return publicOptions;
5170
+ }
5171
+
4987
5172
  const defaultWidgetOptions$e = {
4988
5173
  matrixBoardSize: [3, 3],
4989
5174
  answers: [[]],
@@ -4993,10 +5178,11 @@ const defaultWidgetOptions$e = {
4993
5178
  };
4994
5179
  const matrixWidgetLogic = {
4995
5180
  name: "matrix",
4996
- defaultWidgetOptions: defaultWidgetOptions$e
5181
+ defaultWidgetOptions: defaultWidgetOptions$e,
5182
+ getPublicWidgetOptions: getMatrixPublicWidgetOptions
4997
5183
  };
4998
5184
 
4999
- const _excluded$9 = ["imageUrl", "imageTop", "imageLeft"];
5185
+ const _excluded$5 = ["imageUrl", "imageTop", "imageLeft"];
5000
5186
  const currentVersion$2 = {
5001
5187
  major: 1,
5002
5188
  minor: 0
@@ -5008,7 +5194,7 @@ const widgetOptionsUpgrades$1 = {
5008
5194
  imageTop,
5009
5195
  imageLeft
5010
5196
  } = v0options,
5011
- rest = _objectWithoutPropertiesLoose(v0options, _excluded$9);
5197
+ rest = _objectWithoutPropertiesLoose(v0options, _excluded$5);
5012
5198
  return _extends({}, rest, {
5013
5199
  image: {
5014
5200
  url: imageUrl,
@@ -5036,6 +5222,12 @@ const measurerWidgetLogic = {
5036
5222
  defaultWidgetOptions: defaultWidgetOptions$d
5037
5223
  };
5038
5224
 
5225
+ const _excluded$4 = ["correctX", "correctRel"];
5226
+ function getNumberLinePublicWidgetOptions(options) {
5227
+ const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$4);
5228
+ return publicOptions;
5229
+ }
5230
+
5039
5231
  const defaultWidgetOptions$c = {
5040
5232
  range: [0, 10],
5041
5233
  labelRange: [null, null],
@@ -5052,9 +5244,25 @@ const defaultWidgetOptions$c = {
5052
5244
  };
5053
5245
  const numberLineWidgetLogic = {
5054
5246
  name: "number-line",
5055
- defaultWidgetOptions: defaultWidgetOptions$c
5247
+ defaultWidgetOptions: defaultWidgetOptions$c,
5248
+ getPublicWidgetOptions: getNumberLinePublicWidgetOptions
5056
5249
  };
5057
5250
 
5251
+ const _excluded$3 = ["answers"];
5252
+ /**
5253
+ * For details on the individual options, see the
5254
+ * PerseusNumericInputWidgetOptions type
5255
+ */
5256
+
5257
+ /**
5258
+ * Given a PerseusNumericInputWidgetOptions object, return a new object with only
5259
+ * the public options that should be exposed to the client.
5260
+ */
5261
+ function getNumericInputPublicWidgetOptions(options) {
5262
+ const publicWidgetOptions = _objectWithoutPropertiesLoose(options, _excluded$3);
5263
+ return publicWidgetOptions;
5264
+ }
5265
+
5058
5266
  const defaultWidgetOptions$b = {
5059
5267
  answers: [{
5060
5268
  value: null,
@@ -5073,9 +5281,27 @@ const defaultWidgetOptions$b = {
5073
5281
  const numericInputWidgetLogic = {
5074
5282
  name: "numeric-input",
5075
5283
  defaultWidgetOptions: defaultWidgetOptions$b,
5076
- defaultAlignment: "inline-block"
5284
+ defaultAlignment: "inline-block",
5285
+ getPublicWidgetOptions: getNumericInputPublicWidgetOptions
5077
5286
  };
5078
5287
 
5288
+ /**
5289
+ * For details on the individual options, see the
5290
+ * PerseusOrdererWidgetOptions type
5291
+ */
5292
+
5293
+ /**
5294
+ * Given a PerseusOrdererWidgetOptions object, return a new object with only
5295
+ * the public options that should be exposed to the client.
5296
+ */
5297
+ function getOrdererPublicWidgetOptions(options) {
5298
+ return {
5299
+ options: options.options,
5300
+ height: options.height,
5301
+ layout: options.layout
5302
+ };
5303
+ }
5304
+
5079
5305
  const defaultWidgetOptions$a = {
5080
5306
  correctOptions: [{
5081
5307
  content: "$x$"
@@ -5088,7 +5314,8 @@ const defaultWidgetOptions$a = {
5088
5314
  };
5089
5315
  const ordererWidgetLogic = {
5090
5316
  name: "orderer",
5091
- defaultWidgetOptions: defaultWidgetOptions$a
5317
+ defaultWidgetOptions: defaultWidgetOptions$a,
5318
+ getPublicWidgetOptions: getOrdererPublicWidgetOptions
5092
5319
  };
5093
5320
 
5094
5321
  const defaultWidgetOptions$9 = {
@@ -5137,6 +5364,21 @@ const phetSimulationWidgetLogic = {
5137
5364
  defaultWidgetOptions: defaultWidgetOptions$6
5138
5365
  };
5139
5366
 
5367
+ const _excluded$2 = ["correct"];
5368
+ /**
5369
+ * For details on the individual options, see the
5370
+ * PerseusPlotterWidgetOptions type
5371
+ */
5372
+
5373
+ /**
5374
+ * Given a PerseusPlotterWidgetOptions object, return a new object with only
5375
+ * the public options that should be exposed to the client.
5376
+ */
5377
+ function getPlotterPublicWidgetOptions(options) {
5378
+ const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$2);
5379
+ return publicOptions;
5380
+ }
5381
+
5140
5382
  const defaultWidgetOptions$5 = {
5141
5383
  scaleY: 1,
5142
5384
  maxY: 10,
@@ -5154,7 +5396,8 @@ const defaultWidgetOptions$5 = {
5154
5396
  };
5155
5397
  const plotterWidgetLogic = {
5156
5398
  name: "plotter",
5157
- defaultWidgetOptions: defaultWidgetOptions$5
5399
+ defaultWidgetOptions: defaultWidgetOptions$5,
5400
+ getPublicWidgetOptions: getPlotterPublicWidgetOptions
5158
5401
  };
5159
5402
 
5160
5403
  const defaultWidgetOptions$4 = {
@@ -5166,7 +5409,7 @@ const pythonProgramWidgetLogic = {
5166
5409
  defaultWidgetOptions: defaultWidgetOptions$4
5167
5410
  };
5168
5411
 
5169
- const _excluded$8 = ["noneOfTheAbove"];
5412
+ const _excluded$1 = ["noneOfTheAbove"];
5170
5413
  const currentVersion = {
5171
5414
  major: 1,
5172
5415
  minor: 0
@@ -5176,7 +5419,7 @@ const widgetOptionsUpgrades = {
5176
5419
  const {
5177
5420
  noneOfTheAbove
5178
5421
  } = v0props,
5179
- rest = _objectWithoutPropertiesLoose(v0props, _excluded$8);
5422
+ rest = _objectWithoutPropertiesLoose(v0props, _excluded$1);
5180
5423
  if (noneOfTheAbove) {
5181
5424
  throw new Error("radio widget v0 no longer supports auto noneOfTheAbove");
5182
5425
  }
@@ -5195,13 +5438,73 @@ const defaultWidgetOptions$3 = {
5195
5438
  deselectEnabled: false
5196
5439
  };
5197
5440
 
5441
+ /**
5442
+ * For details on the individual options, see the
5443
+ * PerseusRadioWidgetOptions type
5444
+ */
5445
+
5446
+ /**
5447
+ * Only the options from each Radio choice that should be exposed to the client.
5448
+ */
5449
+
5450
+ /**
5451
+ * Given a PerseusRadioChoice object, return a new object with only the public
5452
+ * data that should be included in the Radio public widget options.
5453
+ */
5454
+ function getRadioChoicePublicData(choice) {
5455
+ const {
5456
+ content,
5457
+ isNoneOfTheAbove,
5458
+ widgets
5459
+ } = choice;
5460
+ return {
5461
+ content,
5462
+ isNoneOfTheAbove,
5463
+ widgets
5464
+ };
5465
+ }
5466
+
5467
+ /**
5468
+ * Given a PerseusRadioWidgetOptions object, return a new object with only
5469
+ * the public options that should be exposed to the client.
5470
+ */
5471
+ function getRadioPublicWidgetOptions(options) {
5472
+ return _extends({}, options, {
5473
+ choices: options.choices.map(getRadioChoicePublicData)
5474
+ });
5475
+ }
5476
+
5198
5477
  const radioWidgetLogic = {
5199
5478
  name: "radio",
5200
5479
  version: currentVersion,
5201
5480
  widgetOptionsUpgrades: widgetOptionsUpgrades,
5202
- defaultWidgetOptions: defaultWidgetOptions$3
5481
+ defaultWidgetOptions: defaultWidgetOptions$3,
5482
+ getPublicWidgetOptions: getRadioPublicWidgetOptions
5203
5483
  };
5204
5484
 
5485
+ /**
5486
+ * For details on the individual options, see the
5487
+ * PerseusSorterWidgetOptions type
5488
+ */
5489
+
5490
+ /**
5491
+ * Given a PerseusSorterWidgetOptions object, return a new object with only
5492
+ * the public options that should be exposed to the client.
5493
+ */
5494
+ function getSorterPublicWidgetOptions(options) {
5495
+ const shuffledCorrect = shuffle$2(options.correct, Math.random, /* ensurePermuted */true);
5496
+ return _extends({}, options, {
5497
+ // Note(Tamara): This does not provide correct answer information any longer.
5498
+ // To maintain compatibility with the original widget options, we are
5499
+ // keeping the key the same. Represents initial state of the cards here.
5500
+ correct: shuffledCorrect,
5501
+ // Note(Tamara): This new key is only added here with "true". There isn't
5502
+ // a place where it is set to false. It indicates that the correct field
5503
+ // has been shuffled and no longer contains correct answer info.
5504
+ isCorrectShuffled: true
5505
+ });
5506
+ }
5507
+
5205
5508
  const defaultWidgetOptions$2 = {
5206
5509
  correct: ["$x$", "$y$", "$z$"],
5207
5510
  layout: "horizontal",
@@ -5209,9 +5512,16 @@ const defaultWidgetOptions$2 = {
5209
5512
  };
5210
5513
  const sorterWidgetLogic = {
5211
5514
  name: "sorter",
5212
- defaultWidgetOptions: defaultWidgetOptions$2
5515
+ defaultWidgetOptions: defaultWidgetOptions$2,
5516
+ getPublicWidgetOptions: getSorterPublicWidgetOptions
5213
5517
  };
5214
5518
 
5519
+ const _excluded = ["answers"];
5520
+ function getTablePublicWidgetOptions(options) {
5521
+ const publicOptions = _objectWithoutPropertiesLoose(options, _excluded);
5522
+ return publicOptions;
5523
+ }
5524
+
5215
5525
  const defaultRows = 4;
5216
5526
  const defaultColumns = 1;
5217
5527
 
@@ -5226,7 +5536,8 @@ const defaultWidgetOptions$1 = {
5226
5536
  };
5227
5537
  const tableWidgetLogic = {
5228
5538
  name: "table",
5229
- defaultWidgetOptions: defaultWidgetOptions$1
5539
+ defaultWidgetOptions: defaultWidgetOptions$1,
5540
+ getPublicWidgetOptions: getTablePublicWidgetOptions
5230
5541
  };
5231
5542
 
5232
5543
  const defaultWidgetOptions = {
@@ -5254,6 +5565,13 @@ function getCurrentVersion(type) {
5254
5565
  minor: 0
5255
5566
  };
5256
5567
  }
5568
+
5569
+ // TODO(LEMS-2870): getPublicWidgetOptionsFunction/PublicWidgetOptionsFunction
5570
+ // need better types
5571
+ const getPublicWidgetOptionsFunction = name => {
5572
+ var _widgets$name$getPubl, _widgets$name;
5573
+ return (_widgets$name$getPubl = (_widgets$name = widgets[name]) == null ? void 0 : _widgets$name.getPublicWidgetOptions) != null ? _widgets$name$getPubl : i => i;
5574
+ };
5257
5575
  function getWidgetOptionsUpgrades(type) {
5258
5576
  const widgetLogic = widgets[type];
5259
5577
  return (widgetLogic == null ? void 0 : widgetLogic.widgetOptionsUpgrades) || {};
@@ -5339,6 +5657,7 @@ var coreWidgetRegistry = /*#__PURE__*/Object.freeze({
5339
5657
  __proto__: null,
5340
5658
  isWidgetRegistered: isWidgetRegistered,
5341
5659
  getCurrentVersion: getCurrentVersion,
5660
+ getPublicWidgetOptionsFunction: getPublicWidgetOptionsFunction,
5342
5661
  getWidgetOptionsUpgrades: getWidgetOptionsUpgrades,
5343
5662
  getDefaultWidgetOptions: getDefaultWidgetOptions,
5344
5663
  getSupportedAlignments: getSupportedAlignments,
@@ -5465,221 +5784,75 @@ function getUpgradedWidgetOptions(oldWidgetOptions) {
5465
5784
  });
5466
5785
  }
5467
5786
 
5468
- /**
5469
- * For details on the individual options, see the
5470
- * PerseusOrdererWidgetOptions type
5471
- */
5472
-
5473
- /**
5474
- * Given a PerseusOrdererWidgetOptions object, return a new object with only
5475
- * the public options that should be exposed to the client.
5476
- */
5477
- function getOrdererPublicWidgetOptions(options) {
5478
- return {
5479
- options: options.options,
5480
- height: options.height,
5481
- layout: options.layout
5482
- };
5483
- }
5484
-
5485
- /**
5486
- * For details on the individual options, see the
5487
- * PerseusCategorizerWidgetOptions type
5488
- */
5489
-
5490
- /**
5491
- * Given a PerseusCategorizerWidgetOptions object, return a new object with only
5492
- * the public options that should be exposed to the client.
5493
- */
5494
- function getCategorizerPublicWidgetOptions(options) {
5495
- return {
5496
- items: options.items,
5497
- categories: options.categories,
5498
- randomizeItems: options.randomizeItems,
5499
- static: options.static
5500
- };
5501
- }
5502
-
5503
- function getCSProgramPublicWidgetOptions(options) {
5504
- return options;
5505
- }
5506
-
5507
- /**
5508
- * For details on the individual options, see the
5509
- * PerseusExpressionWidgetOptions type
5510
- */
5511
-
5512
- /**
5513
- * Given a PerseusExpressionWidgetOptions object, return a new object with only
5514
- * the public options that should be exposed to the client.
5515
- */
5516
- function getExpressionPublicWidgetOptions(options) {
5517
- return {
5518
- buttonSets: options.buttonSets,
5519
- functions: options.functions,
5520
- times: options.times,
5521
- visibleLabel: options.visibleLabel,
5522
- ariaLabel: options.ariaLabel,
5523
- buttonsVisible: options.buttonsVisible
5524
- };
5525
- }
5526
-
5527
- const _excluded$7 = ["correct"];
5528
- function getGrapherPublicWidgetOptions(options) {
5529
- const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$7);
5530
- return publicOptions;
5531
- }
5532
-
5533
- const _excluded$6 = ["correct"];
5534
- function getInteractiveGraphPublicWidgetOptions(options) {
5535
- const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$6);
5536
- return publicOptions;
5537
- }
5538
-
5539
- const _excluded$5 = ["answers"];
5540
- /**
5541
- * For details on the individual options, see the
5542
- * PerseusLabelImageWidgetOptions type
5543
- */
5544
-
5545
- function getLabelImagePublicWidgetOptions(options) {
5546
- return _extends({}, options, {
5547
- markers: options.markers.map(getLabelImageMarkerPublicData)
5787
+ function splitPerseusItem(originalItem) {
5788
+ var _item$widgets;
5789
+ const item = _.clone(originalItem);
5790
+ const originalWidgets = (_item$widgets = item.widgets) != null ? _item$widgets : {};
5791
+ const upgradedWidgets = getUpgradedWidgetOptions(originalWidgets);
5792
+ const splitWidgets = {};
5793
+ for (const [id, widget] of Object.entries(upgradedWidgets)) {
5794
+ const publicWidgetOptionsFun = getPublicWidgetOptionsFunction(widget.type);
5795
+ splitWidgets[id] = _extends({}, widget, {
5796
+ options: publicWidgetOptionsFun(widget.options)
5797
+ });
5798
+ }
5799
+ return _extends({}, item, {
5800
+ widgets: splitWidgets
5548
5801
  });
5549
5802
  }
5550
- function getLabelImageMarkerPublicData(marker) {
5551
- const publicData = _objectWithoutPropertiesLoose(marker, _excluded$5);
5552
- return publicData;
5553
- }
5554
-
5555
- /**
5556
- * For details on the individual options, see the
5557
- * PerseusSorterWidgetOptions type
5558
- */
5559
-
5560
- /**
5561
- * Given a PerseusSorterWidgetOptions object, return a new object with only
5562
- * the public options that should be exposed to the client.
5563
- */
5564
- function getSorterPublicWidgetOptions(options) {
5565
- return {
5566
- // Note(Tamara): This does not provide correct answer information any longer.
5567
- // To maintain compatibility with the original widget options, we are
5568
- // keeping the key the same. Represents initial state of the cards here.
5569
- correct: options.correct.slice().sort(),
5570
- padding: options.padding,
5571
- layout: options.layout
5572
- };
5573
- }
5574
-
5575
- /**
5576
- * For details on the individual options, see the
5577
- * PerseusDropdownWidgetOptions type
5578
- */
5579
-
5580
- /**
5581
- * Given a PerseusDropdownWidgetOptions object, return a new object with only
5582
- * the public options that should be exposed to the client.
5583
- */
5584
- function getDropdownPublicWidgetOptions(options) {
5585
- return {
5586
- choices: options.choices.map(choice => ({
5587
- content: choice.content
5588
- })),
5589
- placeholder: options.placeholder,
5590
- static: options.static,
5591
- visibleLabel: options.visibleLabel,
5592
- ariaLabel: options.ariaLabel
5593
- };
5594
- }
5595
-
5596
- const _excluded$4 = ["answers"];
5597
- /**
5598
- * For details on the individual options, see the
5599
- * PerseusNumericInputWidgetOptions type
5600
- */
5601
-
5602
- /**
5603
- * Given a PerseusNumericInputWidgetOptions object, return a new object with only
5604
- * the public options that should be exposed to the client.
5605
- */
5606
- function getNumericInputPublicWidgetOptions(options) {
5607
- const publicWidgetOptions = _objectWithoutPropertiesLoose(options, _excluded$4);
5608
- return publicWidgetOptions;
5609
- }
5610
-
5611
- const _excluded$3 = ["correctX", "correctRel"];
5612
- function getNumberLinePublicWidgetOptions(options) {
5613
- const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$3);
5614
- return publicOptions;
5615
- }
5616
-
5617
- /**
5618
- * For details on the individual options, see the
5619
- * PerseusRadioWidgetOptions type
5620
- */
5621
-
5622
- /**
5623
- * Only the options from each Radio choice that should be exposed to the client.
5624
- */
5625
5803
 
5626
- /**
5627
- * Given a PerseusRadioChoice object, return a new object with only the public
5628
- * data that should be included in the Radio public widget options.
5629
- */
5630
- function getRadioChoicePublicData(choice) {
5631
- const {
5632
- content,
5633
- isNoneOfTheAbove,
5634
- widgets
5635
- } = choice;
5636
- return {
5637
- content,
5638
- isNoneOfTheAbove,
5639
- widgets
5804
+ /* Note(tamara): Brought over from the perseus package packages/perseus/src/util.ts file.
5805
+ May be useful to bring other perseus package utilities here. Contains utility functions
5806
+ and types used across multiple widgets for randomization and shuffling. */
5807
+ const seededRNG = function seededRNG(seed) {
5808
+ let randomSeed = seed;
5809
+ return function () {
5810
+ // Robert Jenkins' 32 bit integer hash function.
5811
+ let seed = randomSeed;
5812
+ seed = seed + 0x7ed55d16 + (seed << 12) & 0xffffffff;
5813
+ seed = (seed ^ 0xc761c23c ^ seed >>> 19) & 0xffffffff;
5814
+ seed = seed + 0x165667b1 + (seed << 5) & 0xffffffff;
5815
+ seed = (seed + 0xd3a2646c ^ seed << 9) & 0xffffffff;
5816
+ seed = seed + 0xfd7046c5 + (seed << 3) & 0xffffffff;
5817
+ seed = (seed ^ 0xb55a4f09 ^ seed >>> 16) & 0xffffffff;
5818
+ return (randomSeed = seed & 0xfffffff) / 0x10000000;
5640
5819
  };
5641
- }
5642
-
5643
- /**
5644
- * Given a PerseusRadioWidgetOptions object, return a new object with only
5645
- * the public options that should be exposed to the client.
5646
- */
5647
- function getRadioPublicWidgetOptions(options) {
5648
- return _extends({}, options, {
5649
- choices: options.choices.map(getRadioChoicePublicData)
5650
- });
5651
- }
5652
-
5653
- const _excluded$2 = ["answers"];
5654
- function getTablePublicWidgetOptions(options) {
5655
- const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$2);
5656
- return publicOptions;
5657
- }
5658
-
5659
- function getIFramePublicWidgetOptions(options) {
5660
- return options;
5661
- }
5662
-
5663
- const _excluded$1 = ["answers"];
5664
- function getMatrixPublicWidgetOptions(options) {
5665
- const publicOptions = _objectWithoutPropertiesLoose(options, _excluded$1);
5666
- return publicOptions;
5667
- }
5668
-
5669
- const _excluded = ["correct"];
5670
- /**
5671
- * For details on the individual options, see the
5672
- * PerseusPlotterWidgetOptions type
5673
- */
5820
+ };
5674
5821
 
5675
- /**
5676
- * Given a PerseusPlotterWidgetOptions object, return a new object with only
5677
- * the public options that should be exposed to the client.
5678
- */
5679
- function getPlotterPublicWidgetOptions(options) {
5680
- const publicOptions = _objectWithoutPropertiesLoose(options, _excluded);
5681
- return publicOptions;
5822
+ // Shuffle an array using a given random seed or function.
5823
+ // If `ensurePermuted` is true, the input and output are guaranteed to be
5824
+ // distinct permutations.
5825
+ function shuffle(array, randomSeed, ensurePermuted = false) {
5826
+ // Always return a copy of the input array
5827
+ const shuffled = _.clone(array);
5828
+
5829
+ // Handle edge cases (input array is empty or uniform)
5830
+ if (!shuffled.length || _.all(shuffled, function (value) {
5831
+ return _.isEqual(value, shuffled[0]);
5832
+ })) {
5833
+ return shuffled;
5834
+ }
5835
+ let random;
5836
+ if (typeof randomSeed === "function") {
5837
+ random = randomSeed;
5838
+ } else {
5839
+ random = seededRNG(randomSeed);
5840
+ }
5841
+ do {
5842
+ // Fischer-Yates shuffle
5843
+ for (let top = shuffled.length; top > 0; top--) {
5844
+ const newEnd = Math.floor(random() * top);
5845
+ const temp = shuffled[newEnd];
5846
+
5847
+ // @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
5848
+ shuffled[newEnd] = shuffled[top - 1];
5849
+ // @ts-expect-error - TS2542 - Index signature in type 'readonly T[]' only permits reading.
5850
+ shuffled[top - 1] = temp;
5851
+ }
5852
+ } while (ensurePermuted && _.isEqual(array, shuffled));
5853
+ return shuffled;
5682
5854
  }
5855
+ const random = seededRNG(new Date().getTime() & 0xffffffff);
5683
5856
 
5684
- export { coreWidgetRegistry as CoreWidgetRegistry, Errors, grapherUtil as GrapherUtil, ItemExtras, PerseusError, PerseusExpressionAnswerFormConsidered, addLibraryVersionToPerseusDebug, addWidget, approximateDeepEqual, approximateEqual, categorizerWidgetLogic as categorizerLogic, csProgramWidgetLogic as csProgramLogic, deepClone, definitionWidgetLogic as definitionLogic, dropdownWidgetLogic as dropdownLogic, explanationWidgetLogic as explanationLogic, expressionWidgetLogic as expressionLogic, getCSProgramPublicWidgetOptions, getCategorizerPublicWidgetOptions, getDecimalSeparator, getDropdownPublicWidgetOptions, getExpressionPublicWidgetOptions, getGrapherPublicWidgetOptions, getIFramePublicWidgetOptions, getInteractiveGraphPublicWidgetOptions, getLabelImagePublicWidgetOptions, getMatrixPublicWidgetOptions, getMatrixSize, getNumberLinePublicWidgetOptions, getNumericInputPublicWidgetOptions, getOrdererPublicWidgetOptions, getPlotterPublicWidgetOptions, getRadioPublicWidgetOptions, getSorterPublicWidgetOptions, getTablePublicWidgetOptions, getUpgradedWidgetOptions, getWidgetIdsFromContent, getWidgetIdsFromContentByType, gradedGroupWidgetLogic as gradedGroupLogic, gradedGroupSetWidgetLogic as gradedGroupSetLogic, grapherWidgetLogic as grapherLogic, groupWidgetLogic as groupLogic, iframeWidgetLogic as iframeLogic, imageWidgetLogic as imageLogic, inputNumberWidgetLogic as inputNumberLogic, interactionWidgetLogic as interactionLogic, interactiveGraphWidgetLogic as interactiveGraphLogic, isFailure, isSuccess, labelImageWidgetLogic as labelImageLogic, libVersion, lockedFigureColorNames, lockedFigureColors, lockedFigureFillStyles, mapObject, matcherWidgetLogic as matcherLogic, matrixWidgetLogic as matrixLogic, measurerWidgetLogic as measurerLogic, numberLineWidgetLogic as numberLineLogic, numericInputWidgetLogic as numericInputLogic, ordererWidgetLogic as ordererLogic, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem, passageWidgetLogic as passageLogic, passageRefWidgetLogic as passageRefLogic, passageRefTargetWidgetLogic as passageRefTargetLogic, phetSimulationWidgetLogic as phetSimulationLogic, plotterWidgetLogic as plotterLogic, plotterPlotTypes, pluck, pythonProgramWidgetLogic as pythonProgramLogic, radioWidgetLogic as radioLogic, sorterWidgetLogic as sorterLogic, tableWidgetLogic as tableLogic, upgradeWidgetInfoToLatestVersion, videoWidgetLogic as videoLogic };
5857
+ export { coreWidgetRegistry as CoreWidgetRegistry, Errors, grapherUtil as GrapherUtil, ItemExtras, PerseusError, PerseusExpressionAnswerFormConsidered, addLibraryVersionToPerseusDebug, addWidget, approximateDeepEqual, approximateEqual, categorizerWidgetLogic as categorizerLogic, csProgramWidgetLogic as csProgramLogic, deepClone, definitionWidgetLogic as definitionLogic, dropdownWidgetLogic as dropdownLogic, explanationWidgetLogic as explanationLogic, expressionWidgetLogic as expressionLogic, getCSProgramPublicWidgetOptions, getCategorizerPublicWidgetOptions, getDecimalSeparator, getDropdownPublicWidgetOptions, getExpressionPublicWidgetOptions, getGrapherPublicWidgetOptions, getIFramePublicWidgetOptions, getInteractiveGraphPublicWidgetOptions, getLabelImagePublicWidgetOptions, getMatcherPublicWidgetOptions, getMatrixPublicWidgetOptions, getMatrixSize, getNumberLinePublicWidgetOptions, getNumericInputPublicWidgetOptions, getOrdererPublicWidgetOptions, getPlotterPublicWidgetOptions, getRadioPublicWidgetOptions, getSorterPublicWidgetOptions, getTablePublicWidgetOptions, getUpgradedWidgetOptions, getWidgetIdsFromContent, getWidgetIdsFromContentByType, gradedGroupWidgetLogic as gradedGroupLogic, gradedGroupSetWidgetLogic as gradedGroupSetLogic, grapherWidgetLogic as grapherLogic, groupWidgetLogic as groupLogic, iframeWidgetLogic as iframeLogic, imageWidgetLogic as imageLogic, inputNumberWidgetLogic as inputNumberLogic, interactionWidgetLogic as interactionLogic, interactiveGraphWidgetLogic as interactiveGraphLogic, isFailure, isSuccess, labelImageWidgetLogic as labelImageLogic, libVersion, lockedFigureColorNames, lockedFigureColors, lockedFigureFillStyles, mapObject, matcherWidgetLogic as matcherLogic, matrixWidgetLogic as matrixLogic, measurerWidgetLogic as measurerLogic, numberLineWidgetLogic as numberLineLogic, numericInputWidgetLogic as numericInputLogic, ordererWidgetLogic as ordererLogic, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem, passageWidgetLogic as passageLogic, passageRefWidgetLogic as passageRefLogic, passageRefTargetWidgetLogic as passageRefTargetLogic, phetSimulationWidgetLogic as phetSimulationLogic, plotterWidgetLogic as plotterLogic, plotterPlotTypes, pluck, pythonProgramWidgetLogic as pythonProgramLogic, radioWidgetLogic as radioLogic, random, seededRNG, shuffle, shuffleMatcher, sorterWidgetLogic as sorterLogic, splitPerseusItem, tableWidgetLogic as tableLogic, upgradeWidgetInfoToLatestVersion, videoWidgetLogic as videoLogic };
5685
5858
  //# sourceMappingURL=index.js.map