@doenet/assignment-viewer 0.1.0-alpha4 → 0.1.0-alpha5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +719 -601
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1649,12 +1649,7 @@ function isSingleDocState(obj) {
1649
1649
  return (
1650
1650
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1651
1651
  typedObj !== null && typeof typedObj === "object" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1652
- typedObj.type === "singleDoc" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && isSingleDocSource(typedObj.source) && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.attempts) && typedObj.attempts.every(
1653
- (attempt) => (
1654
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1655
- attempt !== null && typeof attempt === "object" && typeof attempt.creditAchieved === "number" && typeof attempt.variant === "number"
1656
- )
1657
- )
1652
+ typedObj.type === "singleDoc" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && isSingleDocSource(typedObj.source) && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && typeof typedObj.attemptNumber === "number" && typeof typedObj.currentVariant === "number" && Array.isArray(typedObj.previousVariants) && typedObj.previousVariants.every((x2) => typeof x2 === "number") && typeof typedObj.initialQuestionCounter === "number" && (typedObj.restrictToVariantSlice === void 0 || isRestrictToVariantSlice(typedObj.restrictToVariantSlice))
1658
1653
  );
1659
1654
  }
1660
1655
  function isSingleDocStateNoSource(obj) {
@@ -1662,12 +1657,7 @@ function isSingleDocStateNoSource(obj) {
1662
1657
  return (
1663
1658
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1664
1659
  typedObj !== null && typeof typedObj === "object" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1665
- typedObj.type === "singleDoc" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.attempts) && typedObj.attempts.every(
1666
- (attempt) => (
1667
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1668
- attempt !== null && typeof attempt === "object" && typeof attempt.creditAchieved === "number" && typeof attempt.variant === "number"
1669
- )
1670
- )
1660
+ typedObj.type === "singleDoc" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && typeof typedObj.attemptNumber === "number" && typeof typedObj.currentVariant === "number" && Array.isArray(typedObj.previousVariants) && typedObj.previousVariants.every((x2) => typeof x2 === "number") && typeof typedObj.initialQuestionCounter === "number" && (typedObj.restrictToVariantSlice === void 0 || isRestrictToVariantSlice(typedObj.restrictToVariantSlice))
1671
1661
  );
1672
1662
  }
1673
1663
  function initializeSingleDocState({
@@ -1684,7 +1674,11 @@ function initializeSingleDocState({
1684
1674
  source,
1685
1675
  initialVariant: variant,
1686
1676
  creditAchieved: 0,
1687
- attempts: [],
1677
+ attemptNumber: 0,
1678
+ currentVariant: 0,
1679
+ previousVariants: [],
1680
+ initialQuestionCounter: 0,
1681
+ doenetStateIdx: null,
1688
1682
  restrictToVariantSlice
1689
1683
  };
1690
1684
  }
@@ -1693,16 +1687,15 @@ function generateNewSingleDocAttempt({
1693
1687
  numActivityVariants,
1694
1688
  initialQuestionCounter,
1695
1689
  questionCounts,
1696
- parentAttempt,
1697
- resetCredit = false
1690
+ parentAttempt
1698
1691
  }) {
1699
- const previousVariants = state.attempts.map((a) => a.variant);
1692
+ const previousVariants = state.previousVariants;
1700
1693
  const numVariants = calcNumVariantsFromState(state, numActivityVariants);
1701
1694
  const numPrevVariants = previousVariants.length;
1702
1695
  const numVariantsToExclude = numPrevVariants % numVariants;
1703
1696
  const numVariantOptions = numVariants - numVariantsToExclude;
1704
1697
  const variantsToExclude = previousVariants.slice(numPrevVariants - numVariantsToExclude, numPrevVariants).sort((a, b2) => a - b2);
1705
- const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attempts.length.toString() + "|" + parentAttempt.toString();
1698
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
1706
1699
  const rng = rngClass$3(rngSeed);
1707
1700
  let selectedVariant = Math.floor(rng() * numVariantOptions) + 1;
1708
1701
  for (const excludedVariant of variantsToExclude) {
@@ -1713,40 +1706,36 @@ function generateNewSingleDocAttempt({
1713
1706
  if (state.restrictToVariantSlice) {
1714
1707
  selectedVariant = (selectedVariant - 1) * state.restrictToVariantSlice.numSlices + state.restrictToVariantSlice.idx;
1715
1708
  }
1716
- const newAttemptState = {
1717
- variant: selectedVariant,
1718
- doenetState: null,
1709
+ const finalQuestionCounter = initialQuestionCounter + questionCounts[state.source.id];
1710
+ const newState = {
1711
+ ...state,
1719
1712
  creditAchieved: 0,
1713
+ attemptNumber: state.attemptNumber + 1,
1714
+ currentVariant: selectedVariant,
1715
+ previousVariants: [...state.previousVariants, selectedVariant],
1716
+ doenetStateIdx: null,
1720
1717
  initialQuestionCounter
1721
1718
  };
1722
- const finalQuestionCounter = initialQuestionCounter + questionCounts[state.source.id];
1723
- const newState = { ...state };
1724
- newState.attempts = [...newState.attempts, newAttemptState];
1725
- if (resetCredit) {
1726
- newState.creditAchieved = 0;
1727
- }
1728
1719
  return { finalQuestionCounter, state: newState };
1729
1720
  }
1730
- function extractSingleDocItemCredit(activityState) {
1721
+ function extractSingleDocItemCredit(activityState, nPrevInShuffleOrder = 0) {
1731
1722
  if (activityState.source.isDescription) {
1732
1723
  return [];
1733
1724
  } else {
1734
1725
  return [
1735
1726
  {
1736
1727
  id: activityState.id,
1737
- score: activityState.creditAchieved
1728
+ score: activityState.creditAchieved,
1729
+ docId: activityState.id,
1730
+ shuffledOrder: nPrevInShuffleOrder + 1,
1731
+ variant: activityState.currentVariant
1738
1732
  }
1739
1733
  ];
1740
1734
  }
1741
1735
  }
1742
- function pruneSingleDocStateForSave(activityState, clearDoenetState) {
1736
+ function pruneSingleDocStateForSave(activityState) {
1743
1737
  const { source: _source, ...newState } = { ...activityState };
1744
- const numAttempts = newState.attempts.length;
1745
- const attempts = newState.attempts.map((attempt, i) => ({
1746
- ...attempt,
1747
- doenetState: clearDoenetState || i !== numAttempts - 1 ? null : attempt.doenetState
1748
- }));
1749
- return { ...newState, attempts };
1738
+ return newState;
1750
1739
  }
1751
1740
  function addSourceToSingleDocState(activityState, source) {
1752
1741
  return { ...activityState, source };
@@ -1765,12 +1754,7 @@ function isSelectState(obj) {
1765
1754
  return (
1766
1755
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1767
1756
  typedObj !== null && typeof typedObj === "object" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1768
- typedObj.type === "select" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && isSelectSource(typedObj.source) && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.latestChildStates) && typedObj.latestChildStates.every(isActivityState) && Array.isArray(typedObj.attempts) && typedObj.attempts.every(
1769
- (attempt) => (
1770
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1771
- attempt !== null && typeof attempt === "object" && typeof attempt.creditAchieved === "number" && Array.isArray(attempt.activities) && attempt.activities.every(isActivityState)
1772
- )
1773
- )
1757
+ typedObj.type === "select" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && isSelectSource(typedObj.source) && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.allChildren) && typedObj.allChildren.every(isActivityState) && typeof typedObj.attemptNumber === "number" && Array.isArray(typedObj.selectedChildren) && typedObj.selectedChildren.every(isActivityState) && Array.isArray(typedObj.previousSelections) && typedObj.previousSelections.every((x2) => typeof x2 === "string") && typeof typedObj.initialQuestionCounter === "number" && (typedObj.restrictToVariantSlice === void 0 || isRestrictToVariantSlice(typedObj.restrictToVariantSlice))
1774
1758
  );
1775
1759
  }
1776
1760
  function isSelectStateNoSource(obj) {
@@ -1778,12 +1762,7 @@ function isSelectStateNoSource(obj) {
1778
1762
  return (
1779
1763
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1780
1764
  typedObj !== null && typeof typedObj === "object" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1781
- typedObj.type === "select" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.latestChildStates) && typedObj.latestChildStates.every(isActivityStateNoSource) && Array.isArray(typedObj.attempts) && typedObj.attempts.every(
1782
- (attempt) => (
1783
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1784
- attempt !== null && typeof attempt === "object" && typeof attempt.creditAchieved === "number" && Array.isArray(attempt.activities) && attempt.activities.every(isActivityStateNoSource)
1785
- )
1786
- )
1765
+ typedObj.type === "select" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.allChildren) && typedObj.allChildren.every(isActivityStateNoSource) && typeof typedObj.attemptNumber === "number" && Array.isArray(typedObj.selectedChildren) && typedObj.selectedChildren.every(isActivityStateNoSource) && Array.isArray(typedObj.previousSelections) && typedObj.previousSelections.every((x2) => typeof x2 === "string") && typeof typedObj.initialQuestionCounter === "number" && (typedObj.restrictToVariantSlice === void 0 || isRestrictToVariantSlice(typedObj.restrictToVariantSlice))
1787
1766
  );
1788
1767
  }
1789
1768
  function initializeSelectState({
@@ -1845,8 +1824,11 @@ function initializeSelectState({
1845
1824
  source,
1846
1825
  initialVariant: variant,
1847
1826
  creditAchieved: 0,
1848
- latestChildStates: childStates,
1849
- attempts: [],
1827
+ allChildren: childStates,
1828
+ attemptNumber: 0,
1829
+ selectedChildren: [],
1830
+ previousSelections: [],
1831
+ initialQuestionCounter: 0,
1850
1832
  restrictToVariantSlice
1851
1833
  };
1852
1834
  }
@@ -1855,16 +1837,15 @@ function generateNewSelectAttempt({
1855
1837
  numActivityVariants,
1856
1838
  initialQuestionCounter,
1857
1839
  questionCounts,
1858
- parentAttempt,
1859
- resetCredit = false
1840
+ parentAttempt
1860
1841
  }) {
1861
1842
  const source = state.source;
1862
1843
  const numToSelect = source.numToSelect;
1863
- const numChildren = state.latestChildStates.length;
1844
+ const numChildren = state.allChildren.length;
1864
1845
  if (numChildren === 0) {
1865
1846
  return { finalQuestionCounter: initialQuestionCounter, state };
1866
1847
  }
1867
- const numVariantsPerChild = state.latestChildStates.map(
1848
+ const numVariantsPerChild = state.allChildren.map(
1868
1849
  (a) => calcNumVariantsFromState(a, numActivityVariants)
1869
1850
  );
1870
1851
  const totalNumOptions = source.selectByVariant ? numVariantsPerChild.reduce((a, c2) => a + c2) : numChildren;
@@ -1889,14 +1870,14 @@ function generateNewSelectAttempt({
1889
1870
  }
1890
1871
  }
1891
1872
  const childIdToIdx = {};
1892
- for (const [idx, child] of state.latestChildStates.entries()) {
1873
+ for (const [idx, child] of state.allChildren.entries()) {
1893
1874
  childIdToIdx[child.id] = idx;
1894
1875
  }
1895
- const numPrevSelected = numToSelect * state.attempts.length;
1876
+ const numPrevSelected = numToSelect * state.attemptNumber;
1896
1877
  const numInGroup = numPrevSelected % totalNumOptions;
1897
1878
  const numLeftInGroup = totalNumOptions - numInGroup;
1898
1879
  const childCountsInGroup = Array(numChildren).fill(0);
1899
- for (const childId of state.attempts.flatMap((attempt) => attempt.activities.map((activity) => activity.id)).reverse().slice(0, numInGroup)) {
1880
+ for (const childId of [...state.previousSelections].reverse().slice(0, numInGroup)) {
1900
1881
  childCountsInGroup[childIdToIdx[childId]]++;
1901
1882
  }
1902
1883
  const childOptionsLeft = childCountsInGroup.flatMap((cnt, idx) => {
@@ -1913,7 +1894,7 @@ function generateNewSelectAttempt({
1913
1894
  if (childOptionsLeft.length !== numLeftInGroup) {
1914
1895
  throw Error("we did something wrong");
1915
1896
  }
1916
- const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attempts.length.toString() + "|" + parentAttempt.toString();
1897
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
1917
1898
  const rng = rngClass$2(rngSeed);
1918
1899
  const childrenChosen = [];
1919
1900
  for (let i = 0; i < Math.min(numToSelect, numLeftInGroup); i++) {
@@ -1940,7 +1921,7 @@ function generateNewSelectAttempt({
1940
1921
  }
1941
1922
  }
1942
1923
  const newActivityStates = [];
1943
- const newActivityOptionStates = [...state.latestChildStates];
1924
+ const newActivityOptionStates = [...state.allChildren];
1944
1925
  let questionCounter = initialQuestionCounter;
1945
1926
  for (const childIdx of childrenChosen) {
1946
1927
  const { finalQuestionCounter: endCounter, state: newState2 } = generateNewActivityAttempt({
@@ -1948,26 +1929,24 @@ function generateNewSelectAttempt({
1948
1929
  numActivityVariants,
1949
1930
  initialQuestionCounter: questionCounter,
1950
1931
  questionCounts,
1951
- parentAttempt: state.attempts.length + 1,
1952
- resetCredit: true
1932
+ parentAttempt: state.attemptNumber + 1
1953
1933
  });
1954
1934
  questionCounter = endCounter;
1955
1935
  newActivityOptionStates[childIdx] = newState2;
1956
1936
  newActivityStates.push(newState2);
1957
1937
  }
1958
- const newAttemptState = {
1959
- activities: newActivityStates,
1960
- creditAchieved: 0,
1961
- initialQuestionCounter
1962
- };
1963
1938
  const newState = {
1964
1939
  ...state,
1965
- latestChildStates: newActivityOptionStates
1940
+ creditAchieved: 0,
1941
+ allChildren: newActivityOptionStates,
1942
+ attemptNumber: state.attemptNumber + 1,
1943
+ selectedChildren: newActivityStates,
1944
+ previousSelections: [
1945
+ ...state.previousSelections,
1946
+ ...newActivityStates.map((s) => s.id)
1947
+ ],
1948
+ initialQuestionCounter
1966
1949
  };
1967
- newState.attempts = [...newState.attempts, newAttemptState];
1968
- if (resetCredit) {
1969
- newState.creditAchieved = 0;
1970
- }
1971
1950
  return { finalQuestionCounter: questionCounter, state: newState };
1972
1951
  }
1973
1952
  function generateNewSingleDocAttemptForMultiSelect({
@@ -1980,35 +1959,25 @@ function generateNewSingleDocAttemptForMultiSelect({
1980
1959
  }) {
1981
1960
  const source = state.source;
1982
1961
  const numToSelect = source.numToSelect;
1983
- if (numToSelect === 1 || state.attempts.length === 0) {
1962
+ if (numToSelect === 1 || state.attemptNumber === 0) {
1984
1963
  throw Error(
1985
1964
  "no reason to call when selecting just one item or for first attempt"
1986
1965
  );
1987
1966
  }
1988
- const numChildren = state.latestChildStates.length;
1967
+ const numChildren = state.allChildren.length;
1989
1968
  const childIdToIdx = {};
1990
- for (const [idx, child] of state.latestChildStates.entries()) {
1969
+ for (const [idx, child] of state.allChildren.entries()) {
1991
1970
  childIdToIdx[child.id] = idx;
1992
1971
  }
1993
- const lastAttempt = state.attempts[state.attempts.length - 1];
1994
- const otherSelectedIds = lastAttempt.activities.filter((a) => a.id !== childId).map((a) => a.id);
1972
+ const otherSelectedIds = state.selectedChildren.filter((a) => a.id !== childId).map((a) => a.id);
1995
1973
  if (otherSelectedIds.length !== numToSelect - 1) {
1996
1974
  throw Error("We made a miscalculation");
1997
1975
  }
1998
- const idOptions = state.latestChildStates.map((s) => s.id).filter((id2) => !otherSelectedIds.includes(id2));
1976
+ const idOptions = state.allChildren.map((s) => s.id).filter((id2) => !otherSelectedIds.includes(id2));
1999
1977
  const numOptions = idOptions.length;
2000
- const prevSelectionOfOptions = state.attempts.flatMap((attempt) => {
2001
- if (attempt.singleItemReplacementIdx === void 0) {
2002
- return attempt.activities.map((activity) => activity.id).filter((id2) => !otherSelectedIds.includes(id2));
2003
- } else {
2004
- const changedId = attempt.activities[attempt.singleItemReplacementIdx].id;
2005
- if (otherSelectedIds.includes(changedId)) {
2006
- return [];
2007
- } else {
2008
- return [changedId];
2009
- }
2010
- }
2011
- });
1978
+ const prevSelectionOfOptions = state.previousSelections.filter(
1979
+ (id2) => !otherSelectedIds.includes(id2)
1980
+ );
2012
1981
  const numPrevSelections = prevSelectionOfOptions.length;
2013
1982
  const numInGroup = numPrevSelections % numOptions;
2014
1983
  const additionalExcludes = prevSelectionOfOptions.slice(
@@ -2016,8 +1985,8 @@ function generateNewSingleDocAttemptForMultiSelect({
2016
1985
  numPrevSelections
2017
1986
  );
2018
1987
  const idxOfAllExcluded = [...otherSelectedIds, ...additionalExcludes].map((id2) => childIdToIdx[id2]).sort((a, b2) => a - b2);
2019
- const slotNum = lastAttempt.activities.map((a) => a.id).indexOf(childId);
2020
- const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attempts.length.toString() + "|" + parentAttempt.toString();
1988
+ const slotNum = state.selectedChildren.map((a) => a.id).indexOf(childId);
1989
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
2021
1990
  const rng = rngClass$2(rngSeed);
2022
1991
  let selectedIdx = Math.floor(
2023
1992
  rng() * (numChildren - idxOfAllExcluded.length)
@@ -2027,86 +1996,92 @@ function generateNewSingleDocAttemptForMultiSelect({
2027
1996
  selectedIdx++;
2028
1997
  }
2029
1998
  }
2030
- const newActivityStates = [...lastAttempt.activities];
2031
- const newActivityOptionStates = [...state.latestChildStates];
1999
+ const newActivityStates = [...state.selectedChildren];
2000
+ const newActivityOptionStates = [...state.allChildren];
2032
2001
  const { finalQuestionCounter, state: newChildState } = generateNewActivityAttempt({
2033
2002
  state: newActivityOptionStates[selectedIdx],
2034
2003
  numActivityVariants,
2035
2004
  initialQuestionCounter,
2036
2005
  questionCounts,
2037
- parentAttempt: state.attempts.length + 1
2006
+ parentAttempt: state.attemptNumber + 1
2038
2007
  });
2039
- const childStatePreserveCredit = { ...newChildState };
2040
- childStatePreserveCredit.creditAchieved = lastAttempt.activities[slotNum].creditAchieved;
2041
- newActivityOptionStates[selectedIdx] = childStatePreserveCredit;
2042
- newActivityStates[slotNum] = childStatePreserveCredit;
2043
- const newAttemptState = {
2044
- activities: newActivityStates,
2045
- creditAchieved: lastAttempt.creditAchieved,
2046
- // keep credit achieved the same
2047
- initialQuestionCounter,
2048
- // indicate that this select attempt is really just about replacing the child from `slotNum`
2049
- singleItemReplacementIdx: slotNum
2050
- };
2008
+ newActivityOptionStates[selectedIdx] = newChildState;
2009
+ newActivityStates[slotNum] = newChildState;
2010
+ const latestOtherCreditAchieved = state.selectedChildren.filter((_2, i) => i != slotNum).map((a) => a.creditAchieved);
2011
+ const creditAchieved = latestOtherCreditAchieved.reduce((a, c2) => a + c2, 0) / state.selectedChildren.length;
2051
2012
  const newState = {
2052
2013
  ...state,
2053
- latestChildStates: newActivityOptionStates,
2054
- attempts: [...state.attempts, newAttemptState]
2014
+ allChildren: newActivityOptionStates,
2015
+ selectedChildren: newActivityStates,
2016
+ creditAchieved,
2017
+ previousSelections: [...state.previousSelections, newChildState.id],
2018
+ initialQuestionCounter
2055
2019
  };
2056
2020
  return { finalQuestionCounter, state: newState };
2057
2021
  }
2058
- function extractSelectItemCredit(activityState) {
2059
- if (activityState.source.numToSelect === 1 && activityState.latestChildStates.every(
2060
- (child) => child.type === "singleDoc"
2061
- )) {
2062
- return [{ id: activityState.id, score: activityState.creditAchieved }];
2063
- } else if (activityState.attempts.length === 0) {
2064
- return [{ id: activityState.id, score: 0 }];
2022
+ function extractSelectItemCredit(activityState, nPrevInShuffleOrder = 0) {
2023
+ if (activityState.attemptNumber === 0) {
2024
+ const nChildren = activityState.allChildren.length;
2025
+ if (nChildren === 0) {
2026
+ return [];
2027
+ }
2028
+ const results = [];
2029
+ let nPrev = nPrevInShuffleOrder;
2030
+ for (let i = 0; i < activityState.source.numToSelect; i++) {
2031
+ const childState = activityState.allChildren[i % nChildren];
2032
+ const next = extractActivityItemCredit(childState, nPrev);
2033
+ nPrev += next.length;
2034
+ results.push(...next);
2035
+ }
2036
+ return results;
2037
+ }
2038
+ if (activityState.source.numToSelect === 1 && activityState.allChildren.every((child) => child.type === "singleDoc")) {
2039
+ return [
2040
+ {
2041
+ id: activityState.id,
2042
+ score: activityState.creditAchieved,
2043
+ docId: activityState.selectedChildren[0].id,
2044
+ shuffledOrder: nPrevInShuffleOrder + 1,
2045
+ variant: activityState.selectedChildren[0].currentVariant
2046
+ }
2047
+ ];
2065
2048
  } else {
2066
- const latestAttempt = activityState.attempts[activityState.attempts.length - 1];
2067
- return latestAttempt.activities.flatMap(
2068
- (state) => extractActivityItemCredit(state)
2069
- );
2049
+ let nPrev = nPrevInShuffleOrder;
2050
+ return activityState.selectedChildren.flatMap((state) => {
2051
+ const next = extractActivityItemCredit(state, nPrev);
2052
+ nPrev += next.length;
2053
+ return next;
2054
+ });
2070
2055
  }
2071
2056
  }
2072
- function pruneSelectStateForSave(activityState, clearDoenetState) {
2057
+ function pruneSelectStateForSave(activityState) {
2073
2058
  const { source: _source, ...newState } = { ...activityState };
2074
- const latestChildStates = newState.latestChildStates.map(
2075
- (child) => pruneActivityStateForSave(child, true)
2059
+ const allChildren2 = newState.allChildren.map(
2060
+ (child) => pruneActivityStateForSave(child)
2076
2061
  );
2077
- const numAttempts = newState.attempts.length;
2078
- const attempts = newState.attempts.map((attempt, i) => ({
2079
- ...attempt,
2080
- activities: attempt.activities.map(
2081
- (state) => pruneActivityStateForSave(
2082
- state,
2083
- i !== numAttempts - 1 || clearDoenetState
2084
- )
2085
- )
2086
- }));
2087
- return { ...newState, latestChildStates, attempts };
2062
+ const selectedChildren = newState.selectedChildren.map(
2063
+ (child) => pruneActivityStateForSave(child)
2064
+ );
2065
+ return { ...newState, allChildren: allChildren2, selectedChildren };
2088
2066
  }
2089
2067
  function addSourceToSelectState(activityState, source) {
2090
- const latestChildStates = activityState.latestChildStates.map((child) => {
2068
+ const allChildren2 = activityState.allChildren.map((child) => {
2069
+ const idx = source.items.findIndex(
2070
+ (src) => src.id === extractSourceId(child.id)
2071
+ );
2072
+ return addSourceToActivityState(child, source.items[idx]);
2073
+ });
2074
+ const selectedChildren = activityState.selectedChildren.map((child) => {
2091
2075
  const idx = source.items.findIndex(
2092
2076
  (src) => src.id === extractSourceId(child.id)
2093
2077
  );
2094
2078
  return addSourceToActivityState(child, source.items[idx]);
2095
2079
  });
2096
- const attempts = activityState.attempts.map((attempt) => ({
2097
- ...attempt,
2098
- activities: attempt.activities.map((state) => {
2099
- const idx = source.items.findIndex(
2100
- (src) => src.id === extractSourceId(state.id)
2101
- );
2102
- return addSourceToActivityState(state, source.items[idx]);
2103
- })
2104
- }));
2105
2080
  return {
2106
2081
  ...activityState,
2107
2082
  source,
2108
- latestChildStates,
2109
- attempts
2083
+ allChildren: allChildren2,
2084
+ selectedChildren
2110
2085
  };
2111
2086
  }
2112
2087
  function calcNumVariantsSelect(source, numActivityVariants) {
@@ -2116,6 +2091,22 @@ function calcNumVariantsSelect(source, numActivityVariants) {
2116
2091
  );
2117
2092
  return Math.floor(numVariantsTot / source.numToSelect);
2118
2093
  }
2094
+ function getNumItemsInSelect(source) {
2095
+ if (source.items.length === 0) {
2096
+ return 0;
2097
+ }
2098
+ const numDocumentsPerItem = getNumItems(source.items[0]);
2099
+ if (source.items.length > 1) {
2100
+ for (const item of source.items.slice(1)) {
2101
+ if (getNumItems(item) !== numDocumentsPerItem) {
2102
+ throw Error(
2103
+ "The case where a select has options with different numbers of documents is not implemented"
2104
+ );
2105
+ }
2106
+ }
2107
+ }
2108
+ return source.numToSelect * numDocumentsPerItem;
2109
+ }
2119
2110
  const rngClass$1 = seedrandom$5.alea;
2120
2111
  function isSequenceSource(obj) {
2121
2112
  const typedObj = obj;
@@ -2132,12 +2123,7 @@ function isSequenceState(obj) {
2132
2123
  return (
2133
2124
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2134
2125
  typedObj !== null && typeof typedObj === "object" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2135
- typedObj.type === "sequence" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && isSequenceSource(typedObj.source) && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.latestChildStates) && typedObj.latestChildStates.every(isActivityState) && Array.isArray(typedObj.attempts) && typedObj.attempts.every(
2136
- (attempt) => (
2137
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2138
- attempt !== null && typeof attempt === "object" && typeof attempt.creditAchieved === "number" && Array.isArray(attempt.activities) && attempt.activities.every(isActivityState)
2139
- )
2140
- )
2126
+ typedObj.type === "sequence" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && isSequenceSource(typedObj.source) && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.allChildren) && typedObj.allChildren.every(isActivityState) && typeof typedObj.attemptNumber === "number" && Array.isArray(typedObj.orderedChildren) && typedObj.orderedChildren.every(isActivityState) && (typedObj.restrictToVariantSlice === void 0 || isRestrictToVariantSlice(typedObj.restrictToVariantSlice))
2141
2127
  );
2142
2128
  }
2143
2129
  function isSequenceStateNoSource(obj) {
@@ -2145,12 +2131,7 @@ function isSequenceStateNoSource(obj) {
2145
2131
  return (
2146
2132
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2147
2133
  typedObj !== null && typeof typedObj === "object" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2148
- typedObj.type === "sequence" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.latestChildStates) && typedObj.latestChildStates.every(isActivityStateNoSource) && Array.isArray(typedObj.attempts) && typedObj.attempts.every(
2149
- (attempt) => (
2150
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2151
- attempt !== null && typeof attempt === "object" && typeof attempt.creditAchieved === "number" && Array.isArray(attempt.activities) && attempt.activities.every(isActivityStateNoSource)
2152
- )
2153
- )
2134
+ typedObj.type === "sequence" && typeof typedObj.id === "string" && (typedObj.parentId === null || typeof typedObj.parentId === "string") && typeof typedObj.initialVariant === "number" && typeof typedObj.creditAchieved === "number" && Array.isArray(typedObj.allChildren) && typedObj.allChildren.every(isActivityStateNoSource) && typeof typedObj.attemptNumber === "number" && Array.isArray(typedObj.orderedChildren) && typedObj.orderedChildren.every(isActivityStateNoSource) && (typedObj.restrictToVariantSlice === void 0 || isRestrictToVariantSlice(typedObj.restrictToVariantSlice))
2154
2135
  );
2155
2136
  }
2156
2137
  function initializeSequenceState({
@@ -2180,8 +2161,9 @@ function initializeSequenceState({
2180
2161
  source,
2181
2162
  initialVariant: variant,
2182
2163
  creditAchieved: 0,
2183
- latestChildStates: childStates,
2184
- attempts: [],
2164
+ allChildren: childStates,
2165
+ attemptNumber: 0,
2166
+ orderedChildren: [],
2185
2167
  restrictToVariantSlice
2186
2168
  };
2187
2169
  }
@@ -2190,12 +2172,11 @@ function generateNewSequenceAttempt({
2190
2172
  numActivityVariants,
2191
2173
  initialQuestionCounter,
2192
2174
  questionCounts,
2193
- parentAttempt,
2194
- resetCredit = false
2175
+ parentAttempt
2195
2176
  }) {
2196
2177
  var _a;
2197
2178
  const source = state.source;
2198
- const childOrder = state.latestChildStates.map((state2) => state2.id);
2179
+ const childOrder = state.allChildren.map((state2) => state2.id);
2199
2180
  if (source.shuffle) {
2200
2181
  let shuffle_ids = function(arr, startInd2, numItems) {
2201
2182
  for (let i = numItems - 1; i > 0; i--) {
@@ -2206,18 +2187,18 @@ function generateNewSequenceAttempt({
2206
2187
  ];
2207
2188
  }
2208
2189
  };
2209
- const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attempts.length.toString() + "|" + parentAttempt.toString();
2190
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
2210
2191
  const rng = rngClass$1(rngSeed);
2211
2192
  let startInd = 0;
2212
- while (startInd < state.latestChildStates.length) {
2213
- while (((_a = state.latestChildStates[startInd]) == null ? void 0 : _a.type) === "singleDoc" && state.latestChildStates[startInd].source.isDescription) {
2193
+ while (startInd < state.allChildren.length) {
2194
+ while (((_a = state.allChildren[startInd]) == null ? void 0 : _a.type) === "singleDoc" && state.allChildren[startInd].source.isDescription) {
2214
2195
  startInd++;
2215
2196
  }
2216
- if (startInd >= state.latestChildStates.length) {
2197
+ if (startInd >= state.allChildren.length) {
2217
2198
  break;
2218
2199
  }
2219
2200
  let numItems = 1;
2220
- while (state.latestChildStates[startInd + numItems] && (state.latestChildStates[startInd + numItems].type !== "singleDoc" || !state.latestChildStates[startInd + numItems].source.isDescription)) {
2201
+ while (state.allChildren[startInd + numItems] && (state.allChildren[startInd + numItems].type !== "singleDoc" || !state.allChildren[startInd + numItems].source.isDescription)) {
2221
2202
  numItems++;
2222
2203
  }
2223
2204
  if (numItems > 1) {
@@ -2227,87 +2208,88 @@ function generateNewSequenceAttempt({
2227
2208
  }
2228
2209
  }
2229
2210
  const orderedChildStates = [];
2230
- const unorderedChildStates = [...state.latestChildStates];
2211
+ const unorderedChildStates = [...state.allChildren];
2231
2212
  let questionCounter = initialQuestionCounter;
2232
2213
  for (const childId of childOrder) {
2233
- const childIdx = state.latestChildStates.findIndex(
2214
+ const childIdx = state.allChildren.findIndex(
2234
2215
  (child) => child.id === childId
2235
2216
  );
2236
- const originalState = state.latestChildStates[childIdx];
2217
+ const originalState = state.allChildren[childIdx];
2237
2218
  const { finalQuestionCounter: endCounter, state: newState2 } = generateNewActivityAttempt({
2238
2219
  state: originalState,
2239
2220
  numActivityVariants,
2240
2221
  initialQuestionCounter: questionCounter,
2241
2222
  questionCounts,
2242
- parentAttempt: state.attempts.length + 1,
2243
- resetCredit: true
2223
+ parentAttempt: state.attemptNumber + 1
2244
2224
  });
2245
2225
  questionCounter = endCounter;
2246
2226
  orderedChildStates.push(newState2);
2247
2227
  unorderedChildStates[childIdx] = newState2;
2248
2228
  }
2249
- const newAttemptState = {
2250
- activities: orderedChildStates,
2251
- creditAchieved: 0
2252
- };
2253
2229
  const newState = {
2254
2230
  ...state,
2255
- latestChildStates: unorderedChildStates
2231
+ creditAchieved: 0,
2232
+ allChildren: unorderedChildStates,
2233
+ attemptNumber: state.attemptNumber + 1,
2234
+ orderedChildren: orderedChildStates
2256
2235
  };
2257
- newState.attempts = [...newState.attempts, newAttemptState];
2258
- if (resetCredit) {
2259
- newState.creditAchieved = 0;
2260
- }
2261
2236
  return { finalQuestionCounter: questionCounter, state: newState };
2262
2237
  }
2263
- function extractSequenceItemCredit(activityState) {
2264
- if (activityState.attempts.length === 0) {
2265
- return [{ id: activityState.id, score: 0 }];
2238
+ function extractSequenceItemCredit(activityState, nPrevInShuffleOrder = 0) {
2239
+ if (activityState.attemptNumber === 0) {
2240
+ let nPrev = nPrevInShuffleOrder;
2241
+ return activityState.allChildren.flatMap((state) => {
2242
+ const next = extractActivityItemCredit(state, nPrev);
2243
+ nPrev += next.length;
2244
+ return next;
2245
+ });
2266
2246
  } else {
2267
- const latestAttempt = activityState.attempts[activityState.attempts.length - 1];
2268
- return latestAttempt.activities.flatMap(
2269
- (state) => extractActivityItemCredit(state)
2270
- );
2247
+ let nPrev = nPrevInShuffleOrder;
2248
+ const inShuffledOrder = activityState.orderedChildren.map((state) => {
2249
+ const next = extractActivityItemCredit(state, nPrev);
2250
+ nPrev += next.length;
2251
+ return { childId: state.id, items: next };
2252
+ });
2253
+ const inOriginalOrder = activityState.allChildren.flatMap((state) => {
2254
+ const childResults = inShuffledOrder.find(
2255
+ (obj) => obj.childId === state.id
2256
+ );
2257
+ if (!childResults) {
2258
+ throw Error("Unreachable");
2259
+ }
2260
+ return childResults.items;
2261
+ });
2262
+ return inOriginalOrder;
2271
2263
  }
2272
2264
  }
2273
- function pruneSequenceStateForSave(activityState, clearDoenetState) {
2265
+ function pruneSequenceStateForSave(activityState) {
2274
2266
  const { source: _source, ...newState } = { ...activityState };
2275
- const latestChildStates = newState.latestChildStates.map(
2276
- (child) => pruneActivityStateForSave(child, true)
2267
+ const allChildren2 = newState.allChildren.map(
2268
+ (child) => pruneActivityStateForSave(child)
2277
2269
  );
2278
- const numAttempts = newState.attempts.length;
2279
- const attempts = newState.attempts.map((attempt, i) => ({
2280
- ...attempt,
2281
- activities: attempt.activities.map(
2282
- (state) => pruneActivityStateForSave(
2283
- state,
2284
- i !== numAttempts - 1 || clearDoenetState
2285
- )
2286
- )
2287
- }));
2288
- return { ...newState, latestChildStates, attempts };
2270
+ const orderedChildren = newState.orderedChildren.map(
2271
+ (child) => pruneActivityStateForSave(child)
2272
+ );
2273
+ return { ...newState, allChildren: allChildren2, orderedChildren };
2289
2274
  }
2290
2275
  function addSourceToSequenceState(activityState, source) {
2291
- const latestChildStates = activityState.latestChildStates.map((child) => {
2276
+ const allChildren2 = activityState.allChildren.map((child) => {
2277
+ const idx = source.items.findIndex(
2278
+ (src) => src.id === extractSourceId(child.id)
2279
+ );
2280
+ return addSourceToActivityState(child, source.items[idx]);
2281
+ });
2282
+ const orderedChildren = activityState.orderedChildren.map((child) => {
2292
2283
  const idx = source.items.findIndex(
2293
2284
  (src) => src.id === extractSourceId(child.id)
2294
2285
  );
2295
2286
  return addSourceToActivityState(child, source.items[idx]);
2296
2287
  });
2297
- const attempts = activityState.attempts.map((attempt) => ({
2298
- ...attempt,
2299
- activities: attempt.activities.map((state) => {
2300
- const idx = source.items.findIndex(
2301
- (src) => src.id === extractSourceId(state.id)
2302
- );
2303
- return addSourceToActivityState(state, source.items[idx]);
2304
- })
2305
- }));
2306
2288
  return {
2307
2289
  ...activityState,
2308
2290
  source,
2309
- latestChildStates,
2310
- attempts
2291
+ allChildren: allChildren2,
2292
+ orderedChildren
2311
2293
  };
2312
2294
  }
2313
2295
  function calcNumVariantsSequence(source, numActivityVariants) {
@@ -2323,6 +2305,14 @@ function calcNumVariantsSequence(source, numActivityVariants) {
2323
2305
  }
2324
2306
  return numVariants;
2325
2307
  }
2308
+ function getNumItemsInSequence(source) {
2309
+ const numDocumentsForEachItem = source.items.map(getNumItems);
2310
+ const totalNumDocuments = numDocumentsForEachItem.reduce(
2311
+ (a, c2) => a + c2,
2312
+ 0
2313
+ );
2314
+ return totalNumDocuments;
2315
+ }
2326
2316
  function commonjsRequire$1(path) {
2327
2317
  throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
2328
2318
  }
@@ -3123,6 +3113,13 @@ function isActivitySource(obj) {
3123
3113
  function isActivityState(obj) {
3124
3114
  return isSingleDocState(obj) || isSelectState(obj) || isSequenceState(obj);
3125
3115
  }
3116
+ function isActivityAndDoenetState(obj) {
3117
+ const typedObj = obj;
3118
+ return (
3119
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
3120
+ typedObj !== null && typeof typedObj === "object" && isActivityState(typedObj.activityState) && Array.isArray(typedObj.doenetStates) && Array.isArray(typedObj.itemAttemptNumbers) && typedObj.itemAttemptNumbers.every((x2) => Number.isInteger(x2) && x2 > 0)
3121
+ );
3122
+ }
3126
3123
  function isActivityStateNoSource(obj) {
3127
3124
  return isSingleDocStateNoSource(obj) || isSelectStateNoSource(obj) || isSequenceStateNoSource(obj);
3128
3125
  }
@@ -3130,7 +3127,9 @@ function isExportedActivityState(obj) {
3130
3127
  const typedObj = obj;
3131
3128
  return (
3132
3129
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
3133
- typedObj !== null && typeof typedObj === "object" && isActivityStateNoSource(typedObj.state) && typeof typedObj.sourceHash === "string" && (typedObj.onSubmission === void 0 || typeof typedObj.onSubmission === "boolean")
3130
+ typedObj !== null && typeof typedObj === "object" && isActivityStateNoSource(typedObj.activityState) && Array.isArray(typedObj.doenetStates) && Array.isArray(typedObj.itemAttemptNumbers) && typedObj.itemAttemptNumbers.every(
3131
+ (x2) => Number.isInteger(x2) && x2 > 0
3132
+ ) && typeof typedObj.sourceHash === "string"
3134
3133
  );
3135
3134
  }
3136
3135
  function initializeActivityState({
@@ -3170,13 +3169,30 @@ function initializeActivityState({
3170
3169
  }
3171
3170
  throw Error("Invalid activity type");
3172
3171
  }
3172
+ function initializeActivityAndDoenetState({
3173
+ source,
3174
+ variant,
3175
+ parentId,
3176
+ numActivityVariants,
3177
+ restrictToVariantSlice
3178
+ }) {
3179
+ const activityState = initializeActivityState({
3180
+ source,
3181
+ variant,
3182
+ parentId,
3183
+ numActivityVariants,
3184
+ restrictToVariantSlice
3185
+ });
3186
+ const numItems = getNumItems(source);
3187
+ const itemAttemptNumbers = Array(numItems).fill(1);
3188
+ return { activityState, doenetStates: [], itemAttemptNumbers };
3189
+ }
3173
3190
  function generateNewActivityAttempt({
3174
3191
  state,
3175
3192
  numActivityVariants,
3176
3193
  initialQuestionCounter,
3177
3194
  questionCounts,
3178
- parentAttempt,
3179
- resetCredit = false
3195
+ parentAttempt
3180
3196
  }) {
3181
3197
  switch (state.type) {
3182
3198
  case "singleDoc": {
@@ -3185,8 +3201,7 @@ function generateNewActivityAttempt({
3185
3201
  numActivityVariants,
3186
3202
  initialQuestionCounter,
3187
3203
  questionCounts,
3188
- parentAttempt,
3189
- resetCredit
3204
+ parentAttempt
3190
3205
  });
3191
3206
  }
3192
3207
  case "select": {
@@ -3195,8 +3210,7 @@ function generateNewActivityAttempt({
3195
3210
  numActivityVariants,
3196
3211
  initialQuestionCounter,
3197
3212
  questionCounts,
3198
- parentAttempt,
3199
- resetCredit
3213
+ parentAttempt
3200
3214
  });
3201
3215
  }
3202
3216
  case "sequence": {
@@ -3205,42 +3219,37 @@ function generateNewActivityAttempt({
3205
3219
  numActivityVariants,
3206
3220
  initialQuestionCounter,
3207
3221
  questionCounts,
3208
- parentAttempt,
3209
- resetCredit
3222
+ parentAttempt
3210
3223
  });
3211
3224
  }
3212
3225
  }
3213
3226
  throw Error("Invalid activity type");
3214
3227
  }
3215
- function generateNewSubActivityAttempt({
3216
- id: id2,
3228
+ function generateNewSingleDocSubAttempt({
3229
+ singleDocId,
3217
3230
  state,
3218
3231
  numActivityVariants,
3219
3232
  initialQuestionCounter,
3220
- questionCounts,
3221
- resetCredit = false
3233
+ questionCounts
3222
3234
  }) {
3223
- if (id2 === state.id) {
3224
- const { state: newActivityState } = generateNewActivityAttempt({
3225
- state,
3226
- numActivityVariants,
3227
- initialQuestionCounter,
3228
- questionCounts,
3229
- parentAttempt: 1,
3230
- resetCredit
3231
- });
3232
- return newActivityState;
3235
+ if (singleDocId === state.id) {
3236
+ throw Error(
3237
+ "Should not call generateSingleDocSubActivityAttempt on entire activity"
3238
+ );
3233
3239
  }
3234
3240
  const allStates = gatherStates(state);
3235
- const subActivityState = allStates[id2];
3236
- if (subActivityState.parentId === null) {
3241
+ const singleDocActivityState = allStates[singleDocId];
3242
+ if (singleDocActivityState.type !== "singleDoc") {
3243
+ throw Error(
3244
+ "generateNewSingleDocSubAttempt implemented only for single documents"
3245
+ );
3246
+ }
3247
+ if (singleDocActivityState.parentId === null) {
3237
3248
  throw Error("Lower lever should have parent");
3238
3249
  }
3239
- const parentState = allStates[subActivityState.parentId];
3240
- if (subActivityState.type === "singleDoc" && parentState.type === "select" && parentState.latestChildStates.every(
3241
- (child) => child.type === "singleDoc"
3242
- )) {
3243
- const grandParentAttempt = parentState.parentId ? allStates[parentState.parentId].attempts.length : 1;
3250
+ const parentState = allStates[singleDocActivityState.parentId];
3251
+ if (parentState.type === "select" && parentState.allChildren.every((child) => child.type === "singleDoc")) {
3252
+ const grandParentAttempt = parentState.parentId ? allStates[parentState.parentId].attemptNumber : 1;
3244
3253
  let newParentState;
3245
3254
  if (parentState.source.numToSelect > 1) {
3246
3255
  ({ state: newParentState } = generateNewSingleDocAttemptForMultiSelect({
@@ -3249,7 +3258,7 @@ function generateNewSubActivityAttempt({
3249
3258
  initialQuestionCounter,
3250
3259
  questionCounts,
3251
3260
  parentAttempt: grandParentAttempt,
3252
- childId: id2
3261
+ childId: singleDocId
3253
3262
  }));
3254
3263
  } else {
3255
3264
  ({ state: newParentState } = generateNewActivityAttempt({
@@ -3267,42 +3276,48 @@ function generateNewSubActivityAttempt({
3267
3276
  });
3268
3277
  } else {
3269
3278
  const { state: newSubActivityState } = generateNewActivityAttempt({
3270
- state: allStates[id2],
3279
+ state: allStates[singleDocId],
3271
3280
  numActivityVariants,
3272
3281
  initialQuestionCounter,
3273
3282
  questionCounts,
3274
- parentAttempt: parentState.attempts.length
3283
+ parentAttempt: parentState.attemptNumber
3275
3284
  });
3276
- allStates[id2] = newSubActivityState;
3285
+ allStates[singleDocId] = newSubActivityState;
3277
3286
  return propagateStateChangeToRoot({
3278
3287
  allStates,
3279
- id: id2
3288
+ id: singleDocId
3280
3289
  });
3281
3290
  }
3282
3291
  }
3283
- function extractActivityItemCredit(activityState) {
3292
+ function extractActivityItemCredit(activityState, nPrevInShuffleOrder = 0) {
3284
3293
  switch (activityState.type) {
3285
3294
  case "singleDoc": {
3286
- return extractSingleDocItemCredit(activityState);
3295
+ return extractSingleDocItemCredit(
3296
+ activityState,
3297
+ nPrevInShuffleOrder
3298
+ );
3287
3299
  }
3288
3300
  case "select": {
3289
- return extractSelectItemCredit(activityState);
3301
+ return extractSelectItemCredit(activityState, nPrevInShuffleOrder);
3290
3302
  }
3291
3303
  case "sequence": {
3292
- return extractSequenceItemCredit(activityState);
3304
+ return extractSequenceItemCredit(
3305
+ activityState,
3306
+ nPrevInShuffleOrder
3307
+ );
3293
3308
  }
3294
3309
  }
3295
3310
  }
3296
- function pruneActivityStateForSave(activityState, clearDoenetState = false) {
3311
+ function pruneActivityStateForSave(activityState) {
3297
3312
  switch (activityState.type) {
3298
3313
  case "singleDoc": {
3299
- return pruneSingleDocStateForSave(activityState, clearDoenetState);
3314
+ return pruneSingleDocStateForSave(activityState);
3300
3315
  }
3301
3316
  case "select": {
3302
- return pruneSelectStateForSave(activityState, clearDoenetState);
3317
+ return pruneSelectStateForSave(activityState);
3303
3318
  }
3304
3319
  case "sequence": {
3305
- return pruneSequenceStateForSave(activityState, clearDoenetState);
3320
+ return pruneSequenceStateForSave(activityState);
3306
3321
  }
3307
3322
  }
3308
3323
  }
@@ -3338,12 +3353,12 @@ function getItemSequence(state) {
3338
3353
  if (state.type === "singleDoc") {
3339
3354
  return [state.id];
3340
3355
  } else {
3341
- const numAttempts = state.attempts.length;
3356
+ const numAttempts = state.attemptNumber;
3342
3357
  if (numAttempts === 0) {
3343
- if (state.latestChildStates.length === 0) {
3358
+ if (state.allChildren.length === 0) {
3344
3359
  return [];
3345
3360
  } else {
3346
- const prelimResult = state.latestChildStates.flatMap(
3361
+ const prelimResult = state.allChildren.flatMap(
3347
3362
  (a) => getItemSequence(a)
3348
3363
  );
3349
3364
  if (state.type === "sequence") {
@@ -3353,9 +3368,11 @@ function getItemSequence(state) {
3353
3368
  }
3354
3369
  }
3355
3370
  }
3356
- return state.attempts[numAttempts - 1].activities.flatMap(
3357
- (a) => getItemSequence(a)
3358
- );
3371
+ if (state.type === "sequence") {
3372
+ return state.orderedChildren.flatMap((a) => getItemSequence(a));
3373
+ } else {
3374
+ return state.selectedChildren.flatMap((a) => getItemSequence(a));
3375
+ }
3359
3376
  }
3360
3377
  }
3361
3378
  function calcNumVariants(source, numActivityVariants) {
@@ -3380,6 +3397,20 @@ function calcNumVariantsFromState(state, numActivityVariants) {
3380
3397
  }
3381
3398
  return numVariants;
3382
3399
  }
3400
+ function getNumItems(source) {
3401
+ switch (source.type) {
3402
+ case "singleDoc": {
3403
+ return 1;
3404
+ }
3405
+ case "select": {
3406
+ return getNumItemsInSelect(source);
3407
+ }
3408
+ case "sequence": {
3409
+ return getNumItemsInSequence(source);
3410
+ }
3411
+ }
3412
+ throw Error("Invalid activity type");
3413
+ }
3383
3414
  function validateIds(source) {
3384
3415
  if (source.id.includes("|")) {
3385
3416
  throw Error(`Id "${source.id}" contains a "|".`);
@@ -3426,7 +3457,7 @@ function gatherStates(state) {
3426
3457
  [state.id]: state
3427
3458
  };
3428
3459
  if (state.type !== "singleDoc") {
3429
- for (const child of state.latestChildStates) {
3460
+ for (const child of state.allChildren) {
3430
3461
  Object.assign(allStates, gatherStates(child));
3431
3462
  }
3432
3463
  }
@@ -3446,31 +3477,25 @@ function propagateStateChangeToRoot({
3446
3477
  if (newParentState.type === "singleDoc") {
3447
3478
  throw Error("Single doc activity cannot be a parent");
3448
3479
  }
3449
- const childIdx = newParentState.latestChildStates.map((child) => child.id).indexOf(id2);
3480
+ const childIdx = newParentState.allChildren.map((child) => child.id).indexOf(id2);
3450
3481
  if (childIdx === -1) {
3451
3482
  throw Error("Something went wrong as parent didn't have child.");
3452
3483
  } else {
3453
- newParentState.latestChildStates = [
3454
- ...newParentState.latestChildStates
3455
- ];
3456
- newParentState.latestChildStates[childIdx] = activityState;
3484
+ newParentState.allChildren = [...newParentState.allChildren];
3485
+ newParentState.allChildren[childIdx] = activityState;
3457
3486
  }
3458
- newParentState.attempts = [...newParentState.attempts];
3459
- const numAttempts = newParentState.attempts.length;
3460
- const lastAttempt = newParentState.attempts[numAttempts - 1] = {
3461
- ...newParentState.attempts[numAttempts - 1]
3462
- };
3463
- const childIdx2 = lastAttempt.activities.map((child) => child.id).indexOf(id2);
3487
+ const childActivities = newParentState.type === "sequence" ? [...newParentState.orderedChildren] : [...newParentState.selectedChildren];
3488
+ const childIdx2 = childActivities.map((child) => child.id).indexOf(id2);
3464
3489
  if (childIdx2 === -1) {
3465
3490
  throw Error(
3466
3491
  "Something went wrong as parent didn't have child in last attempt."
3467
3492
  );
3468
3493
  }
3469
- lastAttempt.activities = [...lastAttempt.activities];
3470
- lastAttempt.activities[childIdx2] = activityState;
3471
- let credit;
3494
+ childActivities[childIdx2] = activityState;
3495
+ let creditAchieved;
3472
3496
  if (newParentState.type === "sequence") {
3473
- const nonDescriptions = newParentState.latestChildStates.filter(
3497
+ newParentState.orderedChildren = childActivities;
3498
+ const nonDescriptions = newParentState.allChildren.filter(
3474
3499
  (activityState2) => activityState2.type !== "singleDoc" || !activityState2.source.isDescription
3475
3500
  );
3476
3501
  let creditWeights = [...newParentState.source.creditWeights ?? []];
@@ -3484,18 +3509,15 @@ function propagateStateChangeToRoot({
3484
3509
  creditWeights = creditWeights.slice(0, nonDescriptions.length);
3485
3510
  const totWeights = creditWeights.reduce((a, c2) => a + c2);
3486
3511
  creditWeights = creditWeights.map((w2) => w2 / totWeights);
3487
- credit = nonDescriptions.reduce(
3512
+ creditAchieved = nonDescriptions.reduce(
3488
3513
  (a, c2, i) => a + c2.creditAchieved * creditWeights[i],
3489
3514
  0
3490
3515
  );
3491
3516
  } else {
3492
- credit = lastAttempt.activities.reduce((a, c2) => a + c2.creditAchieved, 0) / lastAttempt.activities.length;
3517
+ newParentState.selectedChildren = childActivities;
3518
+ creditAchieved = childActivities.reduce((a, c2) => a + c2.creditAchieved, 0) / childActivities.length;
3493
3519
  }
3494
- lastAttempt.creditAchieved = Math.max(lastAttempt.creditAchieved, credit);
3495
- newParentState.creditAchieved = Math.max(
3496
- newParentState.creditAchieved,
3497
- credit
3498
- );
3520
+ newParentState.creditAchieved = creditAchieved;
3499
3521
  return propagateStateChangeToRoot({
3500
3522
  allStates,
3501
3523
  id: newParentState.id
@@ -3508,6 +3530,13 @@ function isSingleDocReportStateMessage(obj) {
3508
3530
  typeObj !== null && typeof typeObj === "object" && typeof typeObj.activityId === "string" && typeof typeObj.docId === "string" && typeof typeObj.score === "number"
3509
3531
  );
3510
3532
  }
3533
+ function isRestrictToVariantSlice(obj) {
3534
+ const typeObj = obj;
3535
+ return (
3536
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
3537
+ typeObj !== null && typeof typeObj === "object" && typeof typeObj.idx === "number" && typeof typeObj.numSlices === "number"
3538
+ );
3539
+ }
3511
3540
  const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
3512
3541
  let nanoid = (size2 = 21) => {
3513
3542
  let id2 = "";
@@ -3653,14 +3682,17 @@ function MdError(props) {
3653
3682
  function SelectActivity({
3654
3683
  flags,
3655
3684
  baseId,
3685
+ maxAttemptsAllowed,
3656
3686
  forceDisable = false,
3657
3687
  forceShowCorrectness = false,
3658
3688
  forceShowSolution = false,
3659
3689
  forceUnsuppressCheckwork = false,
3660
3690
  linkSettings,
3661
3691
  darkMode = "light",
3662
- showAnswerTitles = false,
3692
+ showAnswerResponseMenu = false,
3693
+ answerResponseCountsByItem = [],
3663
3694
  state,
3695
+ doenetStates,
3664
3696
  reportScoreAndStateCallback,
3665
3697
  checkRender,
3666
3698
  checkHidden,
@@ -3668,66 +3700,62 @@ function SelectActivity({
3668
3700
  generateNewItemAttempt,
3669
3701
  hasRenderedCallback,
3670
3702
  reportVisibility = false,
3671
- reportVisibilityCallback
3703
+ reportVisibilityCallback,
3704
+ itemAttemptNumbers,
3705
+ itemSequence
3672
3706
  }) {
3673
- const latestAttempt = state.attempts.length > 0 ? state.attempts[state.attempts.length - 1] : null;
3674
3707
  const selectedActivities = [];
3675
3708
  const selectedIds = [];
3676
- if (latestAttempt) {
3677
- for (const activity of latestAttempt.activities) {
3678
- selectedActivities.push(
3679
- /* @__PURE__ */ jsxRuntimeExports$1.jsx(
3680
- Activity,
3681
- {
3682
- state: activity,
3683
- flags,
3684
- baseId,
3685
- forceDisable,
3686
- forceShowCorrectness,
3687
- forceShowSolution,
3688
- forceUnsuppressCheckwork,
3689
- linkSettings,
3690
- darkMode,
3691
- showAnswerTitles,
3692
- reportScoreAndStateCallback,
3693
- checkRender,
3694
- checkHidden,
3695
- allowItemAttemptButtons,
3696
- generateNewItemAttempt,
3697
- hasRenderedCallback,
3698
- reportVisibility,
3699
- reportVisibilityCallback
3700
- },
3701
- activity.id
3702
- )
3703
- );
3704
- selectedIds.push(activity.id);
3705
- }
3709
+ for (const activity of state.selectedChildren) {
3710
+ selectedActivities.push(
3711
+ /* @__PURE__ */ jsxRuntimeExports$1.jsx(
3712
+ Activity,
3713
+ {
3714
+ state: activity,
3715
+ doenetStates,
3716
+ flags,
3717
+ baseId,
3718
+ maxAttemptsAllowed,
3719
+ forceDisable,
3720
+ forceShowCorrectness,
3721
+ forceShowSolution,
3722
+ forceUnsuppressCheckwork,
3723
+ linkSettings,
3724
+ darkMode,
3725
+ showAnswerResponseMenu,
3726
+ answerResponseCountsByItem,
3727
+ reportScoreAndStateCallback,
3728
+ checkRender,
3729
+ checkHidden,
3730
+ allowItemAttemptButtons,
3731
+ generateNewItemAttempt,
3732
+ hasRenderedCallback,
3733
+ reportVisibility,
3734
+ reportVisibilityCallback,
3735
+ itemAttemptNumbers,
3736
+ itemSequence
3737
+ },
3738
+ activity.id
3739
+ )
3740
+ );
3741
+ selectedIds.push(activity.id);
3706
3742
  }
3707
- return /* @__PURE__ */ jsxRuntimeExports$1.jsx(
3708
- "div",
3709
- {
3710
- hidden: !checkRender(state),
3711
- children: /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { children: selectedActivities })
3712
- },
3713
- // Replace the activity in the DOM when a new attempt is created,
3714
- // except preserve it if just a single item was replaced with the other items staying unchanged.
3715
- state.attempts.filter(
3716
- (x2) => x2.singleItemReplacementIdx === void 0
3717
- ).length
3718
- );
3743
+ return /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { hidden: !checkRender(state), children: /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { children: selectedActivities }) }, state.attemptNumber);
3719
3744
  }
3720
3745
  function SequenceActivity({
3721
3746
  flags,
3722
3747
  baseId,
3748
+ maxAttemptsAllowed,
3723
3749
  forceDisable = false,
3724
3750
  forceShowCorrectness = false,
3725
3751
  forceShowSolution = false,
3726
3752
  forceUnsuppressCheckwork = false,
3727
3753
  linkSettings,
3728
3754
  darkMode = "light",
3729
- showAnswerTitles = false,
3755
+ showAnswerResponseMenu = false,
3756
+ answerResponseCountsByItem = [],
3730
3757
  state,
3758
+ doenetStates,
3731
3759
  reportScoreAndStateCallback,
3732
3760
  checkRender,
3733
3761
  checkHidden,
@@ -3735,41 +3763,45 @@ function SequenceActivity({
3735
3763
  generateNewItemAttempt,
3736
3764
  hasRenderedCallback,
3737
3765
  reportVisibility = false,
3738
- reportVisibilityCallback
3766
+ reportVisibilityCallback,
3767
+ itemAttemptNumbers,
3768
+ itemSequence
3739
3769
  }) {
3740
- const latestAttempt = state.attempts.length > 0 ? state.attempts[state.attempts.length - 1] : null;
3741
3770
  const activityList = [];
3742
- if (latestAttempt) {
3743
- for (const activity of latestAttempt.activities) {
3744
- activityList.push(
3745
- /* @__PURE__ */ jsxRuntimeExports$1.jsx(
3746
- Activity,
3747
- {
3748
- state: activity,
3749
- flags,
3750
- baseId,
3751
- forceDisable,
3752
- forceShowCorrectness,
3753
- forceShowSolution,
3754
- forceUnsuppressCheckwork,
3755
- linkSettings,
3756
- darkMode,
3757
- showAnswerTitles,
3758
- reportScoreAndStateCallback,
3759
- checkRender,
3760
- checkHidden,
3761
- allowItemAttemptButtons,
3762
- generateNewItemAttempt,
3763
- hasRenderedCallback,
3764
- reportVisibility,
3765
- reportVisibilityCallback
3766
- },
3767
- activity.id
3768
- )
3769
- );
3770
- }
3771
+ for (const activity of state.orderedChildren) {
3772
+ activityList.push(
3773
+ /* @__PURE__ */ jsxRuntimeExports$1.jsx(
3774
+ Activity,
3775
+ {
3776
+ state: activity,
3777
+ doenetStates,
3778
+ flags,
3779
+ baseId,
3780
+ maxAttemptsAllowed,
3781
+ forceDisable,
3782
+ forceShowCorrectness,
3783
+ forceShowSolution,
3784
+ forceUnsuppressCheckwork,
3785
+ linkSettings,
3786
+ darkMode,
3787
+ showAnswerResponseMenu,
3788
+ answerResponseCountsByItem,
3789
+ reportScoreAndStateCallback,
3790
+ checkRender,
3791
+ checkHidden,
3792
+ allowItemAttemptButtons,
3793
+ generateNewItemAttempt,
3794
+ hasRenderedCallback,
3795
+ reportVisibility,
3796
+ reportVisibilityCallback,
3797
+ itemAttemptNumbers,
3798
+ itemSequence
3799
+ },
3800
+ activity.id
3801
+ )
3802
+ );
3771
3803
  }
3772
- return /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { hidden: !checkRender(state), children: activityList }, state.attempts.length);
3804
+ return /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { hidden: !checkRender(state), children: activityList }, state.attemptNumber);
3773
3805
  }
3774
3806
  var __defProp3 = Object.defineProperty;
3775
3807
  var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -30569,7 +30601,7 @@ var encBase64 = { exports: {} };
30569
30601
  return CryptoJS.enc.Base64;
30570
30602
  });
30571
30603
  })(encBase64);
30572
- const viewerIframeJsSource = '(function() {\n "use strict";\n document.addEventListener("DOMContentLoaded", () => {\n if (typeof window.renderDoenetViewerToContainer !== "function") {\n return messageParentFromViewer({\n error: "Invalid DoenetML version or DoenetML package not found"\n });\n }\n const callbackOverrides = {};\n const callbackNames = [\n "reportScoreAndStateCallback",\n "setIsInErrorState",\n "generatedVariantCallback",\n "documentStructureCallback",\n "initializedCallback",\n "setErrorsAndWarningsCallback"\n ];\n for (const callback of callbackNames) {\n callbackOverrides[callback] = haveCallbacks.includes(callback) ? (args) => {\n messageParentFromViewer({\n callback,\n args\n });\n } : void 0;\n }\n window.renderDoenetViewerToContainer(\n document.getElementById("root"),\n void 0,\n {\n ...doenetViewerProps,\n externalVirtualKeyboardProvided: true,\n ...callbackOverrides\n }\n );\n });\n window.addEventListener("message", (e) => {\n var _a, _b;\n if (e.origin !== window.parent.location.origin) {\n return;\n }\n if (((_a = e.data.subject) == null ? void 0 : _a.startsWith("SPLICE")) && !((_b = e.data.subject) == null ? void 0 : _b.endsWith("response"))) {\n window.parent.postMessage(e.data);\n }\n });\n function messageParentFromViewer(data) {\n window.parent.postMessage(\n {\n origin: viewerId,\n data\n },\n window.parent.origin\n );\n }\n})();\n';
30604
+ const viewerIframeJsSource = '(function() {\n "use strict";\n document.addEventListener("DOMContentLoaded", async () => {\n let pause100 = function() {\n return new Promise((resolve, _reject) => {\n setTimeout(resolve, 100);\n });\n };\n for (let i = 0; i < 10; i++) {\n if (typeof window.renderDoenetViewerToContainer === "function") {\n break;\n }\n await pause100();\n }\n if (typeof window.renderDoenetViewerToContainer !== "function") {\n return messageParentFromViewer({\n error: "Invalid DoenetML version or DoenetML package not found"\n });\n }\n const callbackOverrides = {};\n const callbackNames = [\n "reportScoreAndStateCallback",\n "setIsInErrorState",\n "generatedVariantCallback",\n "documentStructureCallback",\n "initializedCallback",\n "setErrorsAndWarningsCallback"\n ];\n for (const callback of callbackNames) {\n callbackOverrides[callback] = haveViewerCallbacks.includes(callback) ? (args) => {\n messageParentFromViewer({\n callback,\n args\n });\n } : void 0;\n }\n window.renderDoenetViewerToContainer(\n document.getElementById("root"),\n void 0,\n {\n ...doenetViewerProps,\n externalVirtualKeyboardProvided: true,\n ...callbackOverrides\n }\n );\n });\n window.addEventListener("message", (e) => {\n var _a, _b;\n if (e.origin !== window.parent.location.origin) {\n return;\n }\n if (((_a = e.data.subject) == null ? void 0 : _a.startsWith("SPLICE")) && !((_b = e.data.subject) == null ? void 0 : _b.endsWith("response"))) {\n window.parent.postMessage(e.data);\n } else if (e.data.subject === "requestAnswerResponses") {\n window.parent.postMessage(e.data);\n }\n });\n function messageParentFromViewer(data) {\n window.parent.postMessage(\n {\n origin: viewerId,\n data\n },\n window.parent.origin\n );\n }\n})();\n';
30573
30605
  var __defProp$2 = Object.defineProperty;
30574
30606
  var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
30575
30607
  var __publicField = (obj, key, value) => __defNormalProp$2(obj, key + "", value);
@@ -43813,7 +43845,7 @@ var utils = {
43813
43845
  canBreak
43814
43846
  };
43815
43847
  function createHtmlForDoenetViewer(id2, doenetML, doenetViewerProps, standaloneUrl, cssUrl) {
43816
- const haveCallbacks = [];
43848
+ const haveViewerCallbacks = [];
43817
43849
  const callbackNames = [
43818
43850
  "reportScoreAndStateCallback",
43819
43851
  "setIsInErrorState",
@@ -43824,7 +43856,7 @@ function createHtmlForDoenetViewer(id2, doenetML, doenetViewerProps, standaloneU
43824
43856
  ];
43825
43857
  for (const callback of callbackNames) {
43826
43858
  if (callback in doenetViewerProps) {
43827
- haveCallbacks.push(callback);
43859
+ haveViewerCallbacks.push(callback);
43828
43860
  }
43829
43861
  }
43830
43862
  return `
@@ -43837,10 +43869,10 @@ function createHtmlForDoenetViewer(id2, doenetML, doenetViewerProps, standaloneU
43837
43869
  <script type="module">
43838
43870
  const viewerId = "${id2}";
43839
43871
  const doenetViewerProps = ${JSON.stringify(doenetViewerProps)};
43840
- const haveCallbacks = ${JSON.stringify(haveCallbacks)};
43872
+ const haveViewerCallbacks = ${JSON.stringify(haveViewerCallbacks)};
43841
43873
 
43842
43874
  // This source code has been compiled by vite and should be directly included.
43843
- // It assumes that viewerId, doenetViewerProps, and haveCallbacks are defined in the global scope.
43875
+ // It assumes that viewerId, doenetViewerProps, and haveViewerCallbacks are defined in the global scope.
43844
43876
  ${viewerIframeJsSource}
43845
43877
  <\/script>
43846
43878
  <div id="root">
@@ -53236,7 +53268,7 @@ function ExternalVirtualKeyboard() {
53236
53268
  }
53237
53269
  );
53238
53270
  }
53239
- const version = "0.7.0-alpha30";
53271
+ const version = "0.7.0-alpha32";
53240
53272
  const latestDoenetmlVersion = version;
53241
53273
  function DoenetViewer({
53242
53274
  doenetML,
@@ -53378,14 +53410,17 @@ function DoenetViewer({
53378
53410
  function SingleDocActivity({
53379
53411
  flags,
53380
53412
  baseId,
53413
+ maxAttemptsAllowed,
53381
53414
  forceDisable = false,
53382
53415
  forceShowCorrectness = false,
53383
53416
  forceShowSolution = false,
53384
53417
  forceUnsuppressCheckwork = false,
53385
53418
  linkSettings,
53386
53419
  darkMode = "light",
53387
- showAnswerTitles = false,
53420
+ showAnswerResponseMenu = false,
53421
+ answerResponseCountsByItem = [],
53388
53422
  state,
53423
+ doenetStates,
53389
53424
  reportScoreAndStateCallback,
53390
53425
  checkRender,
53391
53426
  checkHidden,
@@ -53393,21 +53428,24 @@ function SingleDocActivity({
53393
53428
  generateNewItemAttempt,
53394
53429
  hasRenderedCallback,
53395
53430
  reportVisibility = false,
53396
- reportVisibilityCallback
53431
+ reportVisibilityCallback,
53432
+ itemAttemptNumbers,
53433
+ itemSequence
53397
53434
  }) {
53398
53435
  const [rendered, setRendered] = useState$3(false);
53399
- const latestAttempt = state.attempts.length > 0 ? state.attempts[state.attempts.length - 1] : null;
53400
- const [attemptNumber, setAttemptNumber] = useState$3(state.attempts.length);
53436
+ const [attemptNumber, setAttemptNumber] = useState$3(state.attemptNumber);
53401
53437
  const [initialDoenetState, setInitialDoenetState] = useState$3(
53402
- latestAttempt ? (
53403
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
53404
- latestAttempt.doenetState
53405
- ) : null
53438
+ state.doenetStateIdx === null ? null : doenetStates[state.doenetStateIdx] ?? null
53406
53439
  );
53407
53440
  const [requestedVariantIndex, setRequestedVariantIndex] = useState$3(
53408
- latestAttempt ? latestAttempt.variant : state.initialVariant
53441
+ state.currentVariant
53409
53442
  );
53410
53443
  const ref = useRef$6(null);
53444
+ const itemIdx = useMemo$4(
53445
+ () => itemSequence.indexOf(state.id),
53446
+ [itemSequence, state.id]
53447
+ );
53448
+ const itemAttemptNumber = itemAttemptNumbers[itemIdx];
53411
53449
  useEffect$5(() => {
53412
53450
  if (reportVisibility && ref.current) {
53413
53451
  const observer = new IntersectionObserver(
@@ -53422,25 +53460,20 @@ function SingleDocActivity({
53422
53460
  };
53423
53461
  }
53424
53462
  }, [reportVisibility, ref, reportVisibilityCallback, state.id]);
53425
- if (state.attempts.length !== attemptNumber) {
53426
- setAttemptNumber(state.attempts.length);
53463
+ if (state.attemptNumber !== attemptNumber) {
53464
+ setAttemptNumber(state.attemptNumber);
53427
53465
  setInitialDoenetState(
53428
- latestAttempt ? (
53429
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
53430
- latestAttempt.doenetState
53431
- ) : null
53432
- );
53433
- setRequestedVariantIndex(
53434
- latestAttempt ? latestAttempt.variant : state.initialVariant
53466
+ state.doenetStateIdx === null ? null : doenetStates[state.doenetStateIdx] ?? null
53435
53467
  );
53468
+ setRequestedVariantIndex(state.currentVariant);
53436
53469
  }
53437
- const initialCounters = latestAttempt ? {
53438
- question: latestAttempt.initialQuestionCounter,
53439
- problem: latestAttempt.initialQuestionCounter,
53440
- exercise: latestAttempt.initialQuestionCounter
53441
- } : void 0;
53470
+ const initialCounters = {
53471
+ question: state.initialQuestionCounter,
53472
+ problem: state.initialQuestionCounter,
53473
+ exercise: state.initialQuestionCounter
53474
+ };
53442
53475
  const source = state.source;
53443
- const showAttemptButton = allowItemAttemptButtons && generateNewItemAttempt !== void 0 && !source.isDescription;
53476
+ const showAttemptButton = allowItemAttemptButtons && generateNewItemAttempt !== void 0 && !source.isDescription && maxAttemptsAllowed !== 1;
53444
53477
  const render3 = checkRender(state);
53445
53478
  const hidden = checkHidden(state);
53446
53479
  return /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { ref, children: /* @__PURE__ */ jsxRuntimeExports$1.jsxs("div", { hidden: !render3 || hidden, style: { minHeight: "100px" }, children: [
@@ -53461,7 +53494,8 @@ function SingleDocActivity({
53461
53494
  forceUnsuppressCheckwork,
53462
53495
  linkSettings,
53463
53496
  darkMode,
53464
- showAnswerTitles,
53497
+ showAnswerResponseMenu,
53498
+ answerResponseCounts: answerResponseCountsByItem[itemIdx],
53465
53499
  addVirtualKeyboard: false,
53466
53500
  initialState: initialDoenetState,
53467
53501
  initializeCounters: initialCounters,
@@ -53471,25 +53505,30 @@ function SingleDocActivity({
53471
53505
  hasRenderedCallback(state.id);
53472
53506
  }
53473
53507
  },
53474
- state.attempts.length
53508
+ state.attemptNumber
53475
53509
  ),
53476
- showAttemptButton ? /* @__PURE__ */ jsxRuntimeExports$1.jsx(
53510
+ showAttemptButton ? /* @__PURE__ */ jsxRuntimeExports$1.jsxs(
53477
53511
  "button",
53478
53512
  {
53479
53513
  hidden: !rendered,
53480
53514
  onClick: () => {
53481
53515
  generateNewItemAttempt(
53482
53516
  state.id,
53483
- (latestAttempt == null ? void 0 : latestAttempt.initialQuestionCounter) ?? 1
53517
+ state.initialQuestionCounter
53484
53518
  );
53485
53519
  },
53520
+ disabled: maxAttemptsAllowed > 0 && itemAttemptNumber >= maxAttemptsAllowed,
53486
53521
  style: {
53487
53522
  marginLeft: "20px",
53488
53523
  backgroundColor: "lightgray",
53489
53524
  borderRadius: "10px",
53490
53525
  padding: "5px 20px"
53491
53526
  },
53492
- children: "New item attempt"
53527
+ children: [
53528
+ "New item attempt",
53529
+ " ",
53530
+ maxAttemptsAllowed > 0 ? `(${(maxAttemptsAllowed - itemAttemptNumber).toString()} left)` : null
53531
+ ]
53493
53532
  }
53494
53533
  ) : null
53495
53534
  ] }) });
@@ -53497,14 +53536,17 @@ function SingleDocActivity({
53497
53536
  function Activity({
53498
53537
  flags,
53499
53538
  baseId,
53539
+ maxAttemptsAllowed,
53500
53540
  forceDisable = false,
53501
53541
  forceShowCorrectness = false,
53502
53542
  forceShowSolution = false,
53503
53543
  forceUnsuppressCheckwork = false,
53504
53544
  linkSettings,
53505
53545
  darkMode = "light",
53506
- showAnswerTitles = false,
53546
+ showAnswerResponseMenu = false,
53547
+ answerResponseCountsByItem = [],
53507
53548
  state,
53549
+ doenetStates,
53508
53550
  reportScoreAndStateCallback,
53509
53551
  checkRender,
53510
53552
  checkHidden,
@@ -53512,7 +53554,9 @@ function Activity({
53512
53554
  generateNewItemAttempt,
53513
53555
  hasRenderedCallback,
53514
53556
  reportVisibility = false,
53515
- reportVisibilityCallback
53557
+ reportVisibilityCallback,
53558
+ itemAttemptNumbers,
53559
+ itemSequence
53516
53560
  }) {
53517
53561
  switch (state.type) {
53518
53562
  case "singleDoc": {
@@ -53521,14 +53565,17 @@ function Activity({
53521
53565
  {
53522
53566
  flags,
53523
53567
  baseId,
53568
+ maxAttemptsAllowed,
53524
53569
  forceDisable,
53525
53570
  forceShowCorrectness,
53526
53571
  forceShowSolution,
53527
53572
  forceUnsuppressCheckwork,
53528
53573
  linkSettings,
53529
53574
  darkMode,
53530
- showAnswerTitles,
53575
+ showAnswerResponseMenu,
53576
+ answerResponseCountsByItem,
53531
53577
  state,
53578
+ doenetStates,
53532
53579
  reportScoreAndStateCallback,
53533
53580
  checkRender,
53534
53581
  checkHidden,
@@ -53536,7 +53583,9 @@ function Activity({
53536
53583
  generateNewItemAttempt,
53537
53584
  hasRenderedCallback,
53538
53585
  reportVisibility,
53539
- reportVisibilityCallback
53586
+ reportVisibilityCallback,
53587
+ itemAttemptNumbers,
53588
+ itemSequence
53540
53589
  }
53541
53590
  );
53542
53591
  }
@@ -53546,14 +53595,17 @@ function Activity({
53546
53595
  {
53547
53596
  flags,
53548
53597
  baseId,
53598
+ maxAttemptsAllowed,
53549
53599
  forceDisable,
53550
53600
  forceShowCorrectness,
53551
53601
  forceShowSolution,
53552
53602
  forceUnsuppressCheckwork,
53553
53603
  linkSettings,
53554
53604
  darkMode,
53555
- showAnswerTitles,
53605
+ showAnswerResponseMenu,
53606
+ answerResponseCountsByItem,
53556
53607
  state,
53608
+ doenetStates,
53557
53609
  reportScoreAndStateCallback,
53558
53610
  checkRender,
53559
53611
  checkHidden,
@@ -53561,7 +53613,9 @@ function Activity({
53561
53613
  generateNewItemAttempt,
53562
53614
  hasRenderedCallback,
53563
53615
  reportVisibility,
53564
- reportVisibilityCallback
53616
+ reportVisibilityCallback,
53617
+ itemAttemptNumbers,
53618
+ itemSequence
53565
53619
  }
53566
53620
  );
53567
53621
  }
@@ -53571,14 +53625,17 @@ function Activity({
53571
53625
  {
53572
53626
  flags,
53573
53627
  baseId,
53628
+ maxAttemptsAllowed,
53574
53629
  forceDisable,
53575
53630
  forceShowCorrectness,
53576
53631
  forceShowSolution,
53577
53632
  forceUnsuppressCheckwork,
53578
53633
  linkSettings,
53579
53634
  darkMode,
53580
- showAnswerTitles,
53635
+ showAnswerResponseMenu,
53636
+ answerResponseCountsByItem,
53581
53637
  state,
53638
+ doenetStates,
53582
53639
  reportScoreAndStateCallback,
53583
53640
  checkRender,
53584
53641
  checkHidden,
@@ -53586,155 +53643,182 @@ function Activity({
53586
53643
  generateNewItemAttempt,
53587
53644
  hasRenderedCallback,
53588
53645
  reportVisibility,
53589
- reportVisibilityCallback
53646
+ reportVisibilityCallback,
53647
+ itemAttemptNumbers,
53648
+ itemSequence
53590
53649
  }
53591
53650
  );
53592
53651
  }
53593
53652
  }
53594
53653
  }
53595
- function activityStateReducer(state, action) {
53654
+ function activityDoenetStateReducer(state, action) {
53655
+ const activityState = state.activityState;
53596
53656
  switch (action.type) {
53597
53657
  case "initialize": {
53598
- return initializeActivityState({
53599
- source: state.source,
53600
- variant: action.variantIndex,
53601
- parentId: null,
53602
- numActivityVariants: action.numActivityVariants
53603
- });
53658
+ const numItems = getNumItems(action.source);
53659
+ return {
53660
+ activityState: initializeActivityState({
53661
+ source: action.source,
53662
+ variant: action.variantIndex,
53663
+ parentId: null,
53664
+ numActivityVariants: action.numActivityVariants
53665
+ }),
53666
+ doenetStates: [],
53667
+ itemAttemptNumbers: Array(numItems).fill(1)
53668
+ };
53604
53669
  }
53605
53670
  case "set": {
53606
- const scoreByItem = extractActivityItemCredit(action.state);
53607
53671
  if (action.allowSaveState) {
53608
- window.postMessage({
53609
- score: action.state.creditAchieved,
53610
- scoreByItem,
53672
+ const itemScores = extractActivityItemCredit(
53673
+ action.state.activityState
53674
+ );
53675
+ const message = {
53676
+ score: action.state.activityState.creditAchieved,
53677
+ itemScores,
53611
53678
  subject: "SPLICE.reportScoreByItem",
53612
53679
  activityId: action.baseId
53613
- });
53680
+ };
53681
+ window.postMessage(message);
53614
53682
  }
53615
53683
  return action.state;
53616
53684
  }
53617
53685
  case "generateNewActivityAttempt": {
53618
- let newActivityState;
53619
- let firstAttempt = false;
53620
- if (!action.id || action.id === state.id) {
53621
- if (state.attempts.length === 0) {
53622
- firstAttempt = true;
53623
- }
53624
- ({ state: newActivityState } = generateNewActivityAttempt({
53625
- state,
53626
- numActivityVariants: action.numActivityVariants,
53627
- initialQuestionCounter: action.initialQuestionCounter,
53628
- questionCounts: action.questionCounts,
53629
- parentAttempt: 1
53630
- }));
53631
- } else {
53632
- newActivityState = generateNewSubActivityAttempt({
53633
- id: action.id,
53634
- state,
53635
- numActivityVariants: action.numActivityVariants,
53636
- initialQuestionCounter: action.initialQuestionCounter,
53637
- questionCounts: action.questionCounts
53638
- });
53686
+ const { state: newActivityState } = generateNewActivityAttempt({
53687
+ state: activityState,
53688
+ numActivityVariants: action.numActivityVariants,
53689
+ initialQuestionCounter: action.initialQuestionCounter,
53690
+ questionCounts: action.questionCounts,
53691
+ parentAttempt: 1
53692
+ });
53693
+ const newItemAttemptNumbers = state.itemAttemptNumbers.map(() => 1);
53694
+ if (action.allowSaveState) {
53695
+ const itemScores = extractActivityItemCredit(newActivityState);
53696
+ const message = {
53697
+ state: {
53698
+ activityState: pruneActivityStateForSave(newActivityState),
53699
+ doenetStates: [],
53700
+ itemAttemptNumbers: newItemAttemptNumbers,
53701
+ sourceHash: action.sourceHash
53702
+ },
53703
+ score: newActivityState.creditAchieved,
53704
+ itemScores,
53705
+ subject: "SPLICE.reportScoreAndState",
53706
+ activityId: action.baseId,
53707
+ newAttempt: true
53708
+ };
53709
+ window.postMessage(message);
53639
53710
  }
53711
+ return {
53712
+ activityState: newActivityState,
53713
+ doenetStates: [],
53714
+ itemAttemptNumbers: newItemAttemptNumbers
53715
+ };
53716
+ }
53717
+ case "generateSingleDocSubActivityAttempt": {
53718
+ if (action.docId === activityState.id) {
53719
+ throw Error(
53720
+ "Should not call generateSingleDocSubActivityAttempt on entire activity"
53721
+ );
53722
+ }
53723
+ const newActivityState = generateNewSingleDocSubAttempt({
53724
+ singleDocId: action.docId,
53725
+ state: activityState,
53726
+ numActivityVariants: action.numActivityVariants,
53727
+ initialQuestionCounter: action.initialQuestionCounter,
53728
+ questionCounts: action.questionCounts
53729
+ });
53730
+ const newDoenetMLStates = [...state.doenetStates];
53731
+ newDoenetMLStates[action.doenetStateIdx] = null;
53732
+ const itemIdx = action.itemSequence.indexOf(action.docId);
53733
+ const newItemAttemptNumbers = [...state.itemAttemptNumbers];
53734
+ newItemAttemptNumbers[itemIdx]++;
53640
53735
  if (action.allowSaveState) {
53641
- const scoreByItem = extractActivityItemCredit(newActivityState);
53642
- if (firstAttempt) {
53643
- window.postMessage({
53644
- score: newActivityState.creditAchieved,
53645
- scoreByItem,
53646
- subject: "SPLICE.reportScoreByItem",
53647
- activityId: action.baseId
53648
- });
53649
- } else {
53650
- const sourceHash = hash(newActivityState.source);
53651
- window.postMessage({
53652
- state: {
53653
- state: pruneActivityStateForSave(
53654
- newActivityState,
53655
- false
53656
- ),
53657
- sourceHash
53658
- },
53659
- score: newActivityState.creditAchieved,
53660
- scoreByItem,
53661
- subject: "SPLICE.reportScoreAndState",
53662
- activityId: action.baseId
53663
- });
53664
- }
53736
+ const itemScores = extractActivityItemCredit(newActivityState);
53737
+ const itemScoresOld = extractActivityItemCredit(activityState);
53738
+ const newAttemptForItem = itemScoresOld.findIndex(
53739
+ (s) => s.id === action.docId || s.docId === action.docId
53740
+ ) + 1;
53741
+ const message = {
53742
+ state: {
53743
+ activityState: pruneActivityStateForSave(newActivityState),
53744
+ doenetStates: newDoenetMLStates,
53745
+ itemAttemptNumbers: newItemAttemptNumbers,
53746
+ sourceHash: action.sourceHash
53747
+ },
53748
+ score: newActivityState.creditAchieved,
53749
+ itemScores,
53750
+ newDoenetStateIdx: action.doenetStateIdx,
53751
+ subject: "SPLICE.reportScoreAndState",
53752
+ activityId: action.baseId,
53753
+ newAttempt: true,
53754
+ newAttemptForItem
53755
+ };
53756
+ window.postMessage(message);
53665
53757
  }
53666
- return newActivityState;
53758
+ return {
53759
+ activityState: newActivityState,
53760
+ doenetStates: newDoenetMLStates,
53761
+ itemAttemptNumbers: newItemAttemptNumbers
53762
+ };
53667
53763
  }
53668
53764
  case "updateSingleState": {
53669
- const newActivityState = updateSingleDocState(action, state);
53765
+ const newActivityDoenetState = updateSingleDocState(action, state);
53670
53766
  if (action.allowSaveState) {
53671
- const scoreByItem = extractActivityItemCredit(newActivityState);
53672
- const sourceHash = hash(newActivityState.source);
53673
- let onSubmission = false;
53674
- const doenetState = action.doenetState;
53675
- if (typeof doenetState === "object" && doenetState !== null && "onSubmission" in doenetState && typeof doenetState.onSubmission === "boolean") {
53676
- onSubmission = doenetState.onSubmission;
53677
- }
53678
- window.postMessage({
53767
+ const newActivityState = newActivityDoenetState.activityState;
53768
+ const itemScores = extractActivityItemCredit(newActivityState);
53769
+ const itemUpdated = action.itemSequence.indexOf(action.docId) + 1;
53770
+ const message = {
53679
53771
  state: {
53680
- state: pruneActivityStateForSave(
53681
- newActivityState,
53682
- false
53683
- ),
53684
- sourceHash,
53685
- onSubmission
53772
+ activityState: pruneActivityStateForSave(newActivityState),
53773
+ sourceHash: action.sourceHash,
53774
+ doenetStates: newActivityDoenetState.doenetStates,
53775
+ itemAttemptNumbers: state.itemAttemptNumbers
53686
53776
  },
53687
53777
  score: newActivityState.creditAchieved,
53688
- scoreByItem,
53778
+ itemScores,
53779
+ itemUpdated,
53780
+ newDoenetStateIdx: action.doenetStateIdx,
53689
53781
  subject: "SPLICE.reportScoreAndState",
53690
53782
  activityId: action.baseId
53691
- });
53783
+ };
53784
+ window.postMessage(message);
53692
53785
  }
53693
- return newActivityState;
53786
+ return newActivityDoenetState;
53694
53787
  }
53695
53788
  }
53696
53789
  throw Error("Invalid activity action");
53697
53790
  }
53698
- function updateSingleDocState(action, state) {
53699
- const allStates = gatherStates(state);
53700
- const newSingleDocState = allStates[action.id] = {
53701
- ...allStates[action.id]
53791
+ function updateSingleDocState(action, activityDoenetState) {
53792
+ const allStates = gatherStates(activityDoenetState.activityState);
53793
+ const newSingleDocState = allStates[action.docId] = {
53794
+ ...allStates[action.docId]
53702
53795
  };
53703
53796
  if (newSingleDocState.type !== "singleDoc") {
53704
53797
  throw Error(
53705
53798
  "Received the wrong type of activity for updateSingleDocState"
53706
53799
  );
53707
53800
  }
53708
- newSingleDocState.creditAchieved = Math.max(
53709
- newSingleDocState.creditAchieved,
53710
- action.creditAchieved
53711
- );
53712
- const newAttempts = newSingleDocState.attempts = [
53713
- ...newSingleDocState.attempts
53714
- ];
53715
- const lastAttempt = {
53716
- ...newAttempts[newSingleDocState.attempts.length - 1],
53717
- doenetState: action.doenetState
53718
- };
53719
- lastAttempt.creditAchieved = Math.max(
53720
- lastAttempt.creditAchieved,
53721
- action.creditAchieved
53722
- );
53723
- newAttempts[newSingleDocState.attempts.length - 1] = lastAttempt;
53801
+ newSingleDocState.creditAchieved = action.creditAchieved;
53802
+ const doenetStates = [...activityDoenetState.doenetStates];
53803
+ doenetStates[action.doenetStateIdx] = action.doenetState;
53804
+ newSingleDocState.doenetStateIdx = action.doenetStateIdx;
53724
53805
  const rootActivityState = propagateStateChangeToRoot({
53725
53806
  allStates,
53726
53807
  id: newSingleDocState.id
53727
53808
  });
53728
- return rootActivityState;
53809
+ return {
53810
+ activityState: rootActivityState,
53811
+ doenetStates,
53812
+ itemAttemptNumbers: activityDoenetState.itemAttemptNumbers
53813
+ };
53729
53814
  }
53730
53815
  function Viewer({
53731
53816
  source,
53732
53817
  flags,
53733
53818
  activityId,
53734
- userId,
53735
- attemptNumber: _attemptNumber = 1,
53736
- variantIndex: initialVariantIndex,
53737
- maxAttemptsAllowed: _maxAttemptsAllowed = Infinity,
53819
+ userId = null,
53820
+ initialVariantIndex,
53821
+ maxAttemptsAllowed = 1,
53738
53822
  itemLevelAttempts = false,
53739
53823
  activityLevelAttempts = false,
53740
53824
  paginate = true,
@@ -53747,38 +53831,48 @@ function Viewer({
53747
53831
  externalVirtualKeyboardProvided: _externalVirtualKeyboardProvided = false,
53748
53832
  linkSettings,
53749
53833
  darkMode = "light",
53750
- showAnswerTitles = false,
53834
+ showAnswerResponseMenu = false,
53835
+ answerResponseCountsByItem = [],
53751
53836
  showTitle = true
53752
53837
  }) {
53753
53838
  const [errMsg, setErrMsg] = useState$3(null);
53754
53839
  const initialPass = useRef$6(true);
53755
- const { numActivityVariants, questionCounts } = useMemo$4(() => {
53840
+ const { numActivityVariants, questionCounts, sourceHash, numItems } = useMemo$4(() => {
53756
53841
  try {
53757
53842
  validateIds(source);
53758
- return gatherDocumentStructure(source);
53843
+ const docStructure = gatherDocumentStructure(source);
53844
+ const sourceHash2 = hash(source);
53845
+ const numItems2 = getNumItems(source);
53846
+ return { ...docStructure, sourceHash: sourceHash2, numItems: numItems2 };
53759
53847
  } catch (e2) {
53760
53848
  const message = e2 instanceof Error ? e2.message : "";
53761
53849
  setErrMsg(`Error in activity source: ${message}`);
53762
- return { numActivityVariants: {}, questionCounts: {} };
53850
+ return {
53851
+ numActivityVariants: {},
53852
+ questionCounts: {},
53853
+ sourceHash: "",
53854
+ numItems: 0
53855
+ };
53763
53856
  }
53764
53857
  }, [source]);
53765
- const [activityState, activityStateDispatch] = useReducer(
53766
- activityStateReducer,
53858
+ const [activityDoenetState, activityDoenetStateDispatch] = useReducer(
53859
+ activityDoenetStateReducer,
53767
53860
  {
53768
53861
  source,
53769
53862
  variant: initialVariantIndex,
53770
53863
  parentId: null,
53771
53864
  numActivityVariants
53772
53865
  },
53773
- initializeActivityState
53866
+ initializeActivityAndDoenetState
53774
53867
  );
53868
+ const activityState = activityDoenetState.activityState;
53775
53869
  const itemSequence = getItemSequence(activityState);
53776
- const numItems = itemSequence.length;
53777
53870
  const [currentItemIdx, setCurrentItemIdx] = useState$3(0);
53778
53871
  const currentItemId = itemSequence[currentItemIdx];
53779
53872
  const [itemsRendered, setItemsRendered] = useState$3([]);
53780
53873
  const [itemsToRender, setItemsToRender] = useState$3([]);
53781
53874
  const [itemsVisible, setItemsVisible] = useState$3([]);
53875
+ const attemptNumber = activityState.attemptNumber;
53782
53876
  function addItemToRender(id2) {
53783
53877
  if (!itemsToRender.includes(id2)) {
53784
53878
  setItemsToRender((was) => {
@@ -53815,7 +53909,7 @@ function Viewer({
53815
53909
  if (initialPass.current) {
53816
53910
  initialPass.current = false;
53817
53911
  } else {
53818
- activityStateDispatch({
53912
+ activityDoenetStateDispatch({
53819
53913
  type: "initialize",
53820
53914
  source,
53821
53915
  variantIndex: initialVariantIndex,
@@ -53827,79 +53921,86 @@ function Viewer({
53827
53921
  const listenersAdded = [];
53828
53922
  const timeoutIdsAdded = [];
53829
53923
  function loadState() {
53830
- return new Promise((resolve, reject2) => {
53831
- const messageId = nanoid();
53832
- window.postMessage({
53833
- subject: "SPLICE.getState",
53834
- messageId,
53835
- activityId,
53836
- userId
53837
- });
53838
- let waitingToLoadState = true;
53839
- let timeoutId = -1;
53840
- const loadStateListener = function(event) {
53841
- if (event.origin !== window.location.origin) {
53842
- return;
53843
- }
53844
- if (event.data.subject === "SPLICE.getState.response" && event.data.messageId === messageId) {
53845
- waitingToLoadState = false;
53846
- if (event.data.success) {
53847
- if (event.data.loadedState) {
53848
- const exportedState = event.data.state;
53849
- if (isExportedActivityState(exportedState)) {
53850
- if (validateStateAndSource(
53851
- exportedState,
53852
- source
53853
- )) {
53854
- const state = addSourceToActivityState(
53855
- exportedState.state,
53924
+ return new Promise(
53925
+ (resolve, reject2) => {
53926
+ const messageId = nanoid();
53927
+ window.postMessage({
53928
+ subject: "SPLICE.getState",
53929
+ messageId,
53930
+ activityId,
53931
+ userId
53932
+ });
53933
+ let waitingToLoadState = true;
53934
+ let timeoutId = -1;
53935
+ const loadStateListener = function(event) {
53936
+ if (event.origin !== window.location.origin) {
53937
+ return;
53938
+ }
53939
+ if (event.data.subject === "SPLICE.getState.response" && event.data.messageId === messageId) {
53940
+ waitingToLoadState = false;
53941
+ if (event.data.success) {
53942
+ if (event.data.loadedState) {
53943
+ const exportedState = event.data.state;
53944
+ if (isExportedActivityState(exportedState)) {
53945
+ if (validateStateAndSource(
53946
+ exportedState,
53856
53947
  source
53857
- );
53858
- resolve(state);
53948
+ )) {
53949
+ const state = addSourceToActivityState(
53950
+ exportedState.activityState,
53951
+ source
53952
+ );
53953
+ resolve({
53954
+ activityState: state,
53955
+ doenetStates: exportedState.doenetStates,
53956
+ itemAttemptNumbers: exportedState.itemAttemptNumbers
53957
+ });
53958
+ } else {
53959
+ reject2(
53960
+ Error(
53961
+ "Received state did not match source"
53962
+ )
53963
+ );
53964
+ }
53859
53965
  } else {
53860
- reject2(
53861
- Error(
53862
- "Received state did not match source"
53863
- )
53864
- );
53966
+ reject2(Error("Received invalid state"));
53865
53967
  }
53866
53968
  } else {
53867
- reject2(Error("Received invalid state"));
53969
+ resolve(null);
53868
53970
  }
53869
53971
  } else {
53870
- resolve(null);
53972
+ reject2(Error("Error loading assignment state"));
53871
53973
  }
53872
- } else {
53873
- reject2(Error("Error loading assignment state"));
53974
+ window.removeEventListener(
53975
+ "message",
53976
+ loadStateListener
53977
+ );
53978
+ clearTimeout(timeoutId);
53874
53979
  }
53875
- window.removeEventListener(
53876
- "message",
53877
- loadStateListener
53878
- );
53879
- clearTimeout(timeoutId);
53880
- }
53881
- };
53882
- window.addEventListener("message", loadStateListener);
53883
- listenersAdded.push(loadStateListener);
53884
- const MESSAGE_TIMEOUT = 15e3;
53885
- timeoutId = setTimeout(() => {
53886
- if (!waitingToLoadState) {
53887
- return;
53888
- }
53889
- reject2(Error("Time out loading assignment state"));
53890
- }, MESSAGE_TIMEOUT);
53891
- timeoutIdsAdded.push(timeoutId);
53892
- });
53980
+ };
53981
+ window.addEventListener("message", loadStateListener);
53982
+ listenersAdded.push(loadStateListener);
53983
+ const MESSAGE_TIMEOUT = 15e3;
53984
+ timeoutId = setTimeout(() => {
53985
+ if (!waitingToLoadState) {
53986
+ return;
53987
+ }
53988
+ reject2(Error("Time out loading assignment state"));
53989
+ }, MESSAGE_TIMEOUT);
53990
+ timeoutIdsAdded.push(timeoutId);
53991
+ }
53992
+ );
53893
53993
  }
53894
53994
  function getNewActivityState() {
53895
53995
  try {
53896
- activityStateDispatch({
53996
+ activityDoenetStateDispatch({
53897
53997
  type: "generateNewActivityAttempt",
53898
53998
  numActivityVariants,
53899
53999
  initialQuestionCounter: 1,
53900
54000
  questionCounts,
53901
54001
  allowSaveState: flags.allowSaveState,
53902
- baseId: activityId
54002
+ baseId: activityId,
54003
+ sourceHash
53903
54004
  });
53904
54005
  } catch (e2) {
53905
54006
  const message = e2 instanceof Error ? e2.message : "";
@@ -53908,8 +54009,8 @@ function Viewer({
53908
54009
  }
53909
54010
  if (flags.allowLoadState) {
53910
54011
  loadState().then((state) => {
53911
- if (isActivityState(state)) {
53912
- activityStateDispatch({
54012
+ if (isActivityAndDoenetState(state)) {
54013
+ activityDoenetStateDispatch({
53913
54014
  type: "set",
53914
54015
  state,
53915
54016
  allowSaveState: flags.allowSaveState,
@@ -53943,7 +54044,8 @@ function Viewer({
53943
54044
  userId,
53944
54045
  source,
53945
54046
  numActivityVariants,
53946
- questionCounts
54047
+ questionCounts,
54048
+ sourceHash
53947
54049
  ]);
53948
54050
  function clickNext() {
53949
54051
  setCurrentItemIdx((was) => Math.min(numItems - 1, was + 1));
@@ -53953,25 +54055,31 @@ function Viewer({
53953
54055
  }
53954
54056
  function reportScoreAndStateCallback(msg) {
53955
54057
  if (isSingleDocReportStateMessage(msg)) {
53956
- activityStateDispatch({
54058
+ activityDoenetStateDispatch({
53957
54059
  type: "updateSingleState",
53958
- id: msg.docId,
54060
+ docId: msg.docId,
53959
54061
  doenetState: msg.state,
54062
+ doenetStateIdx: itemSequence.indexOf(msg.docId),
54063
+ itemSequence,
53960
54064
  creditAchieved: msg.score,
53961
54065
  allowSaveState: flags.allowSaveState,
53962
- baseId: activityId
54066
+ baseId: activityId,
54067
+ sourceHash
53963
54068
  });
53964
54069
  }
53965
54070
  }
53966
54071
  function generateNewItemAttempt(id2, initialQuestionCounter) {
53967
- activityStateDispatch({
53968
- type: "generateNewActivityAttempt",
53969
- id: id2,
54072
+ activityDoenetStateDispatch({
54073
+ type: "generateSingleDocSubActivityAttempt",
54074
+ docId: id2,
54075
+ doenetStateIdx: itemSequence.indexOf(id2),
54076
+ itemSequence,
53970
54077
  numActivityVariants,
53971
54078
  initialQuestionCounter,
53972
54079
  questionCounts,
53973
54080
  allowSaveState: flags.allowSaveState,
53974
- baseId: activityId
54081
+ baseId: activityId,
54082
+ sourceHash
53975
54083
  });
53976
54084
  setItemsRendered((was) => {
53977
54085
  const idx = was.indexOf(id2);
@@ -54027,13 +54135,14 @@ function Viewer({
54027
54135
  });
54028
54136
  }
54029
54137
  function generateActivityAttempt() {
54030
- activityStateDispatch({
54138
+ activityDoenetStateDispatch({
54031
54139
  type: "generateNewActivityAttempt",
54032
54140
  numActivityVariants,
54033
54141
  initialQuestionCounter: 1,
54034
54142
  questionCounts,
54035
54143
  allowSaveState: flags.allowSaveState,
54036
- baseId: activityId
54144
+ baseId: activityId,
54145
+ sourceHash
54037
54146
  });
54038
54147
  setItemsRendered([]);
54039
54148
  setCurrentItemIdx(0);
@@ -54116,18 +54225,22 @@ function Viewer({
54116
54225
  }
54117
54226
  )
54118
54227
  ] }),
54119
- activityLevelAttempts ? /* @__PURE__ */ jsxRuntimeExports$1.jsx(
54228
+ activityLevelAttempts && maxAttemptsAllowed !== 1 ? /* @__PURE__ */ jsxRuntimeExports$1.jsxs(
54120
54229
  "button",
54121
54230
  {
54122
54231
  onClick: generateActivityAttempt,
54123
- disabled: numItems === 0,
54232
+ disabled: numItems === 0 || maxAttemptsAllowed > 0 && attemptNumber >= maxAttemptsAllowed,
54124
54233
  style: {
54125
54234
  marginLeft: "30px",
54126
54235
  backgroundColor: "lightgray",
54127
54236
  borderRadius: "10px",
54128
54237
  padding: "5px 20px"
54129
54238
  },
54130
- children: "New attempt"
54239
+ children: [
54240
+ "New attempt",
54241
+ " ",
54242
+ maxAttemptsAllowed > 0 ? `(${(maxAttemptsAllowed - attemptNumber).toString()} left)` : null
54243
+ ]
54131
54244
  }
54132
54245
  ) : null
54133
54246
  ] }) }),
@@ -54144,14 +54257,17 @@ function Viewer({
54144
54257
  {
54145
54258
  flags,
54146
54259
  baseId: activityId,
54260
+ maxAttemptsAllowed,
54147
54261
  forceDisable,
54148
54262
  forceShowCorrectness,
54149
54263
  forceShowSolution,
54150
54264
  forceUnsuppressCheckwork,
54151
54265
  linkSettings,
54152
54266
  darkMode,
54153
- showAnswerTitles,
54267
+ showAnswerResponseMenu,
54268
+ answerResponseCountsByItem,
54154
54269
  state: activityState,
54270
+ doenetStates: activityDoenetState.doenetStates,
54155
54271
  reportScoreAndStateCallback,
54156
54272
  checkRender,
54157
54273
  checkHidden,
@@ -54159,7 +54275,9 @@ function Viewer({
54159
54275
  generateNewItemAttempt,
54160
54276
  hasRenderedCallback,
54161
54277
  reportVisibility: !paginate,
54162
- reportVisibilityCallback
54278
+ reportVisibilityCallback,
54279
+ itemAttemptNumbers: activityDoenetState.itemAttemptNumbers,
54280
+ itemSequence
54163
54281
  }
54164
54282
  )
54165
54283
  ] });
@@ -54182,10 +54300,9 @@ function ActivityViewer({
54182
54300
  source,
54183
54301
  flags: specifiedFlags = {},
54184
54302
  activityId = "a",
54185
- userId,
54186
- attemptNumber = 1,
54303
+ userId = null,
54187
54304
  requestedVariantIndex,
54188
- maxAttemptsAllowed = Infinity,
54305
+ maxAttemptsAllowed = 1,
54189
54306
  itemLevelAttempts = false,
54190
54307
  activityLevelAttempts = false,
54191
54308
  paginate = true,
@@ -54198,11 +54315,12 @@ function ActivityViewer({
54198
54315
  externalVirtualKeyboardProvided = false,
54199
54316
  linkSettings,
54200
54317
  darkMode = "light",
54201
- showAnswerTitles = false,
54318
+ showAnswerResponseMenu = false,
54319
+ answerResponseCountsByItem = [],
54202
54320
  includeVariantSelector: _includeVariantSelector = false,
54203
54321
  showTitle = true
54204
54322
  }) {
54205
- const [variantIndex, setVariantIndex] = useState$3(null);
54323
+ const [initialVariantIndex, setInitialVariantIndex] = useState$3(null);
54206
54324
  const thisPropSet = {
54207
54325
  source: JSON.stringify(source),
54208
54326
  activityId,
@@ -54221,14 +54339,14 @@ function ActivityViewer({
54221
54339
  if (foundPropChange) {
54222
54340
  if (requestedVariantIndex === void 0) {
54223
54341
  const rng = rngClass((/* @__PURE__ */ new Date()).toString());
54224
- setVariantIndex(Math.floor(rng() * 1e6) + 1);
54342
+ setInitialVariantIndex(Math.floor(rng() * 1e6) + 1);
54225
54343
  } else {
54226
- setVariantIndex(
54344
+ setInitialVariantIndex(
54227
54345
  Number.isInteger(requestedVariantIndex) ? requestedVariantIndex : 1
54228
54346
  );
54229
54347
  }
54230
54348
  }
54231
- if (variantIndex === null) {
54349
+ if (initialVariantIndex === null) {
54232
54350
  return null;
54233
54351
  }
54234
54352
  return /* @__PURE__ */ jsxRuntimeExports$1.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntimeExports$1.jsx(
@@ -54238,8 +54356,7 @@ function ActivityViewer({
54238
54356
  flags,
54239
54357
  activityId,
54240
54358
  userId,
54241
- attemptNumber,
54242
- variantIndex,
54359
+ initialVariantIndex,
54243
54360
  maxAttemptsAllowed,
54244
54361
  itemLevelAttempts,
54245
54362
  activityLevelAttempts,
@@ -54253,7 +54370,8 @@ function ActivityViewer({
54253
54370
  externalVirtualKeyboardProvided,
54254
54371
  linkSettings,
54255
54372
  darkMode,
54256
- showAnswerTitles,
54373
+ showAnswerResponseMenu,
54374
+ answerResponseCountsByItem,
54257
54375
  showTitle
54258
54376
  }
54259
54377
  ) });