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

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 +852 -639
  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
  }
@@ -1692,17 +1686,15 @@ function generateNewSingleDocAttempt({
1692
1686
  state,
1693
1687
  numActivityVariants,
1694
1688
  initialQuestionCounter,
1695
- questionCounts,
1696
- parentAttempt,
1697
- resetCredit = false
1689
+ parentAttempt
1698
1690
  }) {
1699
- const previousVariants = state.attempts.map((a) => a.variant);
1691
+ const previousVariants = state.previousVariants;
1700
1692
  const numVariants = calcNumVariantsFromState(state, numActivityVariants);
1701
1693
  const numPrevVariants = previousVariants.length;
1702
1694
  const numVariantsToExclude = numPrevVariants % numVariants;
1703
1695
  const numVariantOptions = numVariants - numVariantsToExclude;
1704
1696
  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();
1697
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
1706
1698
  const rng = rngClass$3(rngSeed);
1707
1699
  let selectedVariant = Math.floor(rng() * numVariantOptions) + 1;
1708
1700
  for (const excludedVariant of variantsToExclude) {
@@ -1713,40 +1705,36 @@ function generateNewSingleDocAttempt({
1713
1705
  if (state.restrictToVariantSlice) {
1714
1706
  selectedVariant = (selectedVariant - 1) * state.restrictToVariantSlice.numSlices + state.restrictToVariantSlice.idx;
1715
1707
  }
1716
- const newAttemptState = {
1717
- variant: selectedVariant,
1718
- doenetState: null,
1708
+ const finalQuestionCounter = initialQuestionCounter + (state.source.isDescription ? 0 : 1);
1709
+ const newState = {
1710
+ ...state,
1719
1711
  creditAchieved: 0,
1712
+ attemptNumber: state.attemptNumber + 1,
1713
+ currentVariant: selectedVariant,
1714
+ previousVariants: [...state.previousVariants, selectedVariant],
1715
+ doenetStateIdx: null,
1720
1716
  initialQuestionCounter
1721
1717
  };
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
1718
  return { finalQuestionCounter, state: newState };
1729
1719
  }
1730
- function extractSingleDocItemCredit(activityState) {
1720
+ function extractSingleDocItemCredit(activityState, nPrevInShuffleOrder = 0) {
1731
1721
  if (activityState.source.isDescription) {
1732
1722
  return [];
1733
1723
  } else {
1734
1724
  return [
1735
1725
  {
1736
1726
  id: activityState.id,
1737
- score: activityState.creditAchieved
1727
+ score: activityState.creditAchieved,
1728
+ docId: activityState.id,
1729
+ shuffledOrder: nPrevInShuffleOrder + 1,
1730
+ variant: activityState.currentVariant
1738
1731
  }
1739
1732
  ];
1740
1733
  }
1741
1734
  }
1742
- function pruneSingleDocStateForSave(activityState, clearDoenetState) {
1735
+ function pruneSingleDocStateForSave(activityState) {
1743
1736
  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 };
1737
+ return newState;
1750
1738
  }
1751
1739
  function addSourceToSingleDocState(activityState, source) {
1752
1740
  return { ...activityState, source };
@@ -1765,12 +1753,7 @@ function isSelectState(obj) {
1765
1753
  return (
1766
1754
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1767
1755
  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
- )
1756
+ 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
1757
  );
1775
1758
  }
1776
1759
  function isSelectStateNoSource(obj) {
@@ -1778,12 +1761,7 @@ function isSelectStateNoSource(obj) {
1778
1761
  return (
1779
1762
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1780
1763
  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
- )
1764
+ 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
1765
  );
1788
1766
  }
1789
1767
  function initializeSelectState({
@@ -1845,8 +1823,11 @@ function initializeSelectState({
1845
1823
  source,
1846
1824
  initialVariant: variant,
1847
1825
  creditAchieved: 0,
1848
- latestChildStates: childStates,
1849
- attempts: [],
1826
+ allChildren: childStates,
1827
+ attemptNumber: 0,
1828
+ selectedChildren: [],
1829
+ previousSelections: [],
1830
+ initialQuestionCounter: 0,
1850
1831
  restrictToVariantSlice
1851
1832
  };
1852
1833
  }
@@ -1854,17 +1835,15 @@ function generateNewSelectAttempt({
1854
1835
  state,
1855
1836
  numActivityVariants,
1856
1837
  initialQuestionCounter,
1857
- questionCounts,
1858
- parentAttempt,
1859
- resetCredit = false
1838
+ parentAttempt
1860
1839
  }) {
1861
1840
  const source = state.source;
1862
1841
  const numToSelect = source.numToSelect;
1863
- const numChildren = state.latestChildStates.length;
1842
+ const numChildren = state.allChildren.length;
1864
1843
  if (numChildren === 0) {
1865
1844
  return { finalQuestionCounter: initialQuestionCounter, state };
1866
1845
  }
1867
- const numVariantsPerChild = state.latestChildStates.map(
1846
+ const numVariantsPerChild = state.allChildren.map(
1868
1847
  (a) => calcNumVariantsFromState(a, numActivityVariants)
1869
1848
  );
1870
1849
  const totalNumOptions = source.selectByVariant ? numVariantsPerChild.reduce((a, c2) => a + c2) : numChildren;
@@ -1889,14 +1868,14 @@ function generateNewSelectAttempt({
1889
1868
  }
1890
1869
  }
1891
1870
  const childIdToIdx = {};
1892
- for (const [idx, child] of state.latestChildStates.entries()) {
1871
+ for (const [idx, child] of state.allChildren.entries()) {
1893
1872
  childIdToIdx[child.id] = idx;
1894
1873
  }
1895
- const numPrevSelected = numToSelect * state.attempts.length;
1874
+ const numPrevSelected = numToSelect * state.attemptNumber;
1896
1875
  const numInGroup = numPrevSelected % totalNumOptions;
1897
1876
  const numLeftInGroup = totalNumOptions - numInGroup;
1898
1877
  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)) {
1878
+ for (const childId of [...state.previousSelections].reverse().slice(0, numInGroup)) {
1900
1879
  childCountsInGroup[childIdToIdx[childId]]++;
1901
1880
  }
1902
1881
  const childOptionsLeft = childCountsInGroup.flatMap((cnt, idx) => {
@@ -1913,7 +1892,7 @@ function generateNewSelectAttempt({
1913
1892
  if (childOptionsLeft.length !== numLeftInGroup) {
1914
1893
  throw Error("we did something wrong");
1915
1894
  }
1916
- const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attempts.length.toString() + "|" + parentAttempt.toString();
1895
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
1917
1896
  const rng = rngClass$2(rngSeed);
1918
1897
  const childrenChosen = [];
1919
1898
  for (let i = 0; i < Math.min(numToSelect, numLeftInGroup); i++) {
@@ -1940,75 +1919,61 @@ function generateNewSelectAttempt({
1940
1919
  }
1941
1920
  }
1942
1921
  const newActivityStates = [];
1943
- const newActivityOptionStates = [...state.latestChildStates];
1922
+ const newActivityOptionStates = [...state.allChildren];
1944
1923
  let questionCounter = initialQuestionCounter;
1945
1924
  for (const childIdx of childrenChosen) {
1946
1925
  const { finalQuestionCounter: endCounter, state: newState2 } = generateNewActivityAttempt({
1947
1926
  state: newActivityOptionStates[childIdx],
1948
1927
  numActivityVariants,
1949
1928
  initialQuestionCounter: questionCounter,
1950
- questionCounts,
1951
- parentAttempt: state.attempts.length + 1,
1952
- resetCredit: true
1929
+ parentAttempt: state.attemptNumber + 1
1953
1930
  });
1954
1931
  questionCounter = endCounter;
1955
1932
  newActivityOptionStates[childIdx] = newState2;
1956
1933
  newActivityStates.push(newState2);
1957
1934
  }
1958
- const newAttemptState = {
1959
- activities: newActivityStates,
1960
- creditAchieved: 0,
1961
- initialQuestionCounter
1962
- };
1963
1935
  const newState = {
1964
1936
  ...state,
1965
- latestChildStates: newActivityOptionStates
1937
+ creditAchieved: 0,
1938
+ allChildren: newActivityOptionStates,
1939
+ attemptNumber: state.attemptNumber + 1,
1940
+ selectedChildren: newActivityStates,
1941
+ previousSelections: [
1942
+ ...state.previousSelections,
1943
+ ...newActivityStates.map((s) => s.id)
1944
+ ],
1945
+ initialQuestionCounter
1966
1946
  };
1967
- newState.attempts = [...newState.attempts, newAttemptState];
1968
- if (resetCredit) {
1969
- newState.creditAchieved = 0;
1970
- }
1971
1947
  return { finalQuestionCounter: questionCounter, state: newState };
1972
1948
  }
1973
1949
  function generateNewSingleDocAttemptForMultiSelect({
1974
1950
  state,
1975
1951
  numActivityVariants,
1976
1952
  initialQuestionCounter,
1977
- questionCounts,
1978
1953
  parentAttempt,
1979
1954
  childId
1980
1955
  }) {
1981
1956
  const source = state.source;
1982
1957
  const numToSelect = source.numToSelect;
1983
- if (numToSelect === 1 || state.attempts.length === 0) {
1958
+ if (numToSelect === 1 || state.attemptNumber === 0) {
1984
1959
  throw Error(
1985
1960
  "no reason to call when selecting just one item or for first attempt"
1986
1961
  );
1987
1962
  }
1988
- const numChildren = state.latestChildStates.length;
1963
+ const numChildren = state.allChildren.length;
1989
1964
  const childIdToIdx = {};
1990
- for (const [idx, child] of state.latestChildStates.entries()) {
1965
+ for (const [idx, child] of state.allChildren.entries()) {
1991
1966
  childIdToIdx[child.id] = idx;
1992
1967
  }
1993
- const lastAttempt = state.attempts[state.attempts.length - 1];
1994
- const otherSelectedIds = lastAttempt.activities.filter((a) => a.id !== childId).map((a) => a.id);
1968
+ const otherSelectedIds = state.selectedChildren.filter((a) => a.id !== childId).map((a) => a.id);
1995
1969
  if (otherSelectedIds.length !== numToSelect - 1) {
1996
1970
  throw Error("We made a miscalculation");
1997
1971
  }
1998
- const idOptions = state.latestChildStates.map((s) => s.id).filter((id2) => !otherSelectedIds.includes(id2));
1972
+ const idOptions = state.allChildren.map((s) => s.id).filter((id2) => !otherSelectedIds.includes(id2));
1999
1973
  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
- });
1974
+ const prevSelectionOfOptions = state.previousSelections.filter(
1975
+ (id2) => !otherSelectedIds.includes(id2)
1976
+ );
2012
1977
  const numPrevSelections = prevSelectionOfOptions.length;
2013
1978
  const numInGroup = numPrevSelections % numOptions;
2014
1979
  const additionalExcludes = prevSelectionOfOptions.slice(
@@ -2016,8 +1981,8 @@ function generateNewSingleDocAttemptForMultiSelect({
2016
1981
  numPrevSelections
2017
1982
  );
2018
1983
  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();
1984
+ const slotNum = state.selectedChildren.map((a) => a.id).indexOf(childId);
1985
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
2021
1986
  const rng = rngClass$2(rngSeed);
2022
1987
  let selectedIdx = Math.floor(
2023
1988
  rng() * (numChildren - idxOfAllExcluded.length)
@@ -2027,86 +1992,91 @@ function generateNewSingleDocAttemptForMultiSelect({
2027
1992
  selectedIdx++;
2028
1993
  }
2029
1994
  }
2030
- const newActivityStates = [...lastAttempt.activities];
2031
- const newActivityOptionStates = [...state.latestChildStates];
1995
+ const newActivityStates = [...state.selectedChildren];
1996
+ const newActivityOptionStates = [...state.allChildren];
2032
1997
  const { finalQuestionCounter, state: newChildState } = generateNewActivityAttempt({
2033
1998
  state: newActivityOptionStates[selectedIdx],
2034
1999
  numActivityVariants,
2035
2000
  initialQuestionCounter,
2036
- questionCounts,
2037
- parentAttempt: state.attempts.length + 1
2001
+ parentAttempt: state.attemptNumber + 1
2038
2002
  });
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
- };
2003
+ newActivityOptionStates[selectedIdx] = newChildState;
2004
+ newActivityStates[slotNum] = newChildState;
2005
+ const latestOtherCreditAchieved = state.selectedChildren.filter((_2, i) => i != slotNum).map((a) => a.creditAchieved);
2006
+ const creditAchieved = latestOtherCreditAchieved.reduce((a, c2) => a + c2, 0) / state.selectedChildren.length;
2051
2007
  const newState = {
2052
2008
  ...state,
2053
- latestChildStates: newActivityOptionStates,
2054
- attempts: [...state.attempts, newAttemptState]
2009
+ allChildren: newActivityOptionStates,
2010
+ selectedChildren: newActivityStates,
2011
+ creditAchieved,
2012
+ previousSelections: [...state.previousSelections, newChildState.id],
2013
+ initialQuestionCounter
2055
2014
  };
2056
2015
  return { finalQuestionCounter, state: newState };
2057
2016
  }
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 }];
2017
+ function extractSelectItemCredit(activityState, nPrevInShuffleOrder = 0) {
2018
+ if (activityState.attemptNumber === 0) {
2019
+ const nChildren = activityState.allChildren.length;
2020
+ if (nChildren === 0) {
2021
+ return [];
2022
+ }
2023
+ const results = [];
2024
+ let nPrev = nPrevInShuffleOrder;
2025
+ for (let i = 0; i < activityState.source.numToSelect; i++) {
2026
+ const childState = activityState.allChildren[i % nChildren];
2027
+ const next = extractActivityItemCredit(childState, nPrev);
2028
+ nPrev += next.length;
2029
+ results.push(...next);
2030
+ }
2031
+ return results;
2032
+ }
2033
+ if (activityState.source.numToSelect === 1 && activityState.allChildren.every((child) => child.type === "singleDoc")) {
2034
+ return [
2035
+ {
2036
+ id: activityState.id,
2037
+ score: activityState.creditAchieved,
2038
+ docId: activityState.selectedChildren[0].id,
2039
+ shuffledOrder: nPrevInShuffleOrder + 1,
2040
+ variant: activityState.selectedChildren[0].currentVariant
2041
+ }
2042
+ ];
2065
2043
  } else {
2066
- const latestAttempt = activityState.attempts[activityState.attempts.length - 1];
2067
- return latestAttempt.activities.flatMap(
2068
- (state) => extractActivityItemCredit(state)
2069
- );
2044
+ let nPrev = nPrevInShuffleOrder;
2045
+ return activityState.selectedChildren.flatMap((state) => {
2046
+ const next = extractActivityItemCredit(state, nPrev);
2047
+ nPrev += next.length;
2048
+ return next;
2049
+ });
2070
2050
  }
2071
2051
  }
2072
- function pruneSelectStateForSave(activityState, clearDoenetState) {
2052
+ function pruneSelectStateForSave(activityState) {
2073
2053
  const { source: _source, ...newState } = { ...activityState };
2074
- const latestChildStates = newState.latestChildStates.map(
2075
- (child) => pruneActivityStateForSave(child, true)
2054
+ const allChildren2 = newState.allChildren.map(
2055
+ (child) => pruneActivityStateForSave(child)
2076
2056
  );
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 };
2057
+ const selectedChildren = newState.selectedChildren.map(
2058
+ (child) => pruneActivityStateForSave(child)
2059
+ );
2060
+ return { ...newState, allChildren: allChildren2, selectedChildren };
2088
2061
  }
2089
2062
  function addSourceToSelectState(activityState, source) {
2090
- const latestChildStates = activityState.latestChildStates.map((child) => {
2063
+ const allChildren2 = activityState.allChildren.map((child) => {
2064
+ const idx = source.items.findIndex(
2065
+ (src) => src.id === extractSourceId(child.id)
2066
+ );
2067
+ return addSourceToActivityState(child, source.items[idx]);
2068
+ });
2069
+ const selectedChildren = activityState.selectedChildren.map((child) => {
2091
2070
  const idx = source.items.findIndex(
2092
2071
  (src) => src.id === extractSourceId(child.id)
2093
2072
  );
2094
2073
  return addSourceToActivityState(child, source.items[idx]);
2095
2074
  });
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
2075
  return {
2106
2076
  ...activityState,
2107
2077
  source,
2108
- latestChildStates,
2109
- attempts
2078
+ allChildren: allChildren2,
2079
+ selectedChildren
2110
2080
  };
2111
2081
  }
2112
2082
  function calcNumVariantsSelect(source, numActivityVariants) {
@@ -2116,6 +2086,22 @@ function calcNumVariantsSelect(source, numActivityVariants) {
2116
2086
  );
2117
2087
  return Math.floor(numVariantsTot / source.numToSelect);
2118
2088
  }
2089
+ function getNumItemsInSelect(source) {
2090
+ if (source.items.length === 0) {
2091
+ return 0;
2092
+ }
2093
+ const numDocumentsPerItem = getNumItems(source.items[0]);
2094
+ if (source.items.length > 1) {
2095
+ for (const item of source.items.slice(1)) {
2096
+ if (getNumItems(item) !== numDocumentsPerItem) {
2097
+ throw Error(
2098
+ "The case where a select has options with different numbers of documents is not implemented"
2099
+ );
2100
+ }
2101
+ }
2102
+ }
2103
+ return source.numToSelect * numDocumentsPerItem;
2104
+ }
2119
2105
  const rngClass$1 = seedrandom$5.alea;
2120
2106
  function isSequenceSource(obj) {
2121
2107
  const typedObj = obj;
@@ -2132,12 +2118,7 @@ function isSequenceState(obj) {
2132
2118
  return (
2133
2119
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2134
2120
  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
- )
2121
+ 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
2122
  );
2142
2123
  }
2143
2124
  function isSequenceStateNoSource(obj) {
@@ -2145,12 +2126,7 @@ function isSequenceStateNoSource(obj) {
2145
2126
  return (
2146
2127
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2147
2128
  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
- )
2129
+ 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
2130
  );
2155
2131
  }
2156
2132
  function initializeSequenceState({
@@ -2180,8 +2156,9 @@ function initializeSequenceState({
2180
2156
  source,
2181
2157
  initialVariant: variant,
2182
2158
  creditAchieved: 0,
2183
- latestChildStates: childStates,
2184
- attempts: [],
2159
+ allChildren: childStates,
2160
+ attemptNumber: 0,
2161
+ orderedChildren: [],
2185
2162
  restrictToVariantSlice
2186
2163
  };
2187
2164
  }
@@ -2189,13 +2166,11 @@ function generateNewSequenceAttempt({
2189
2166
  state,
2190
2167
  numActivityVariants,
2191
2168
  initialQuestionCounter,
2192
- questionCounts,
2193
- parentAttempt,
2194
- resetCredit = false
2169
+ parentAttempt
2195
2170
  }) {
2196
2171
  var _a;
2197
2172
  const source = state.source;
2198
- const childOrder = state.latestChildStates.map((state2) => state2.id);
2173
+ const childOrder = state.allChildren.map((state2) => state2.id);
2199
2174
  if (source.shuffle) {
2200
2175
  let shuffle_ids = function(arr, startInd2, numItems) {
2201
2176
  for (let i = numItems - 1; i > 0; i--) {
@@ -2206,18 +2181,18 @@ function generateNewSequenceAttempt({
2206
2181
  ];
2207
2182
  }
2208
2183
  };
2209
- const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attempts.length.toString() + "|" + parentAttempt.toString();
2184
+ const rngSeed = state.initialVariant.toString() + "|" + state.id.toString() + "|" + state.attemptNumber.toString() + "|" + parentAttempt.toString();
2210
2185
  const rng = rngClass$1(rngSeed);
2211
2186
  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) {
2187
+ while (startInd < state.allChildren.length) {
2188
+ while (((_a = state.allChildren[startInd]) == null ? void 0 : _a.type) === "singleDoc" && state.allChildren[startInd].source.isDescription) {
2214
2189
  startInd++;
2215
2190
  }
2216
- if (startInd >= state.latestChildStates.length) {
2191
+ if (startInd >= state.allChildren.length) {
2217
2192
  break;
2218
2193
  }
2219
2194
  let numItems = 1;
2220
- while (state.latestChildStates[startInd + numItems] && (state.latestChildStates[startInd + numItems].type !== "singleDoc" || !state.latestChildStates[startInd + numItems].source.isDescription)) {
2195
+ while (state.allChildren[startInd + numItems] && (state.allChildren[startInd + numItems].type !== "singleDoc" || !state.allChildren[startInd + numItems].source.isDescription)) {
2221
2196
  numItems++;
2222
2197
  }
2223
2198
  if (numItems > 1) {
@@ -2227,87 +2202,87 @@ function generateNewSequenceAttempt({
2227
2202
  }
2228
2203
  }
2229
2204
  const orderedChildStates = [];
2230
- const unorderedChildStates = [...state.latestChildStates];
2205
+ const unorderedChildStates = [...state.allChildren];
2231
2206
  let questionCounter = initialQuestionCounter;
2232
2207
  for (const childId of childOrder) {
2233
- const childIdx = state.latestChildStates.findIndex(
2208
+ const childIdx = state.allChildren.findIndex(
2234
2209
  (child) => child.id === childId
2235
2210
  );
2236
- const originalState = state.latestChildStates[childIdx];
2211
+ const originalState = state.allChildren[childIdx];
2237
2212
  const { finalQuestionCounter: endCounter, state: newState2 } = generateNewActivityAttempt({
2238
2213
  state: originalState,
2239
2214
  numActivityVariants,
2240
2215
  initialQuestionCounter: questionCounter,
2241
- questionCounts,
2242
- parentAttempt: state.attempts.length + 1,
2243
- resetCredit: true
2216
+ parentAttempt: state.attemptNumber + 1
2244
2217
  });
2245
2218
  questionCounter = endCounter;
2246
2219
  orderedChildStates.push(newState2);
2247
2220
  unorderedChildStates[childIdx] = newState2;
2248
2221
  }
2249
- const newAttemptState = {
2250
- activities: orderedChildStates,
2251
- creditAchieved: 0
2252
- };
2253
2222
  const newState = {
2254
2223
  ...state,
2255
- latestChildStates: unorderedChildStates
2224
+ creditAchieved: 0,
2225
+ allChildren: unorderedChildStates,
2226
+ attemptNumber: state.attemptNumber + 1,
2227
+ orderedChildren: orderedChildStates
2256
2228
  };
2257
- newState.attempts = [...newState.attempts, newAttemptState];
2258
- if (resetCredit) {
2259
- newState.creditAchieved = 0;
2260
- }
2261
2229
  return { finalQuestionCounter: questionCounter, state: newState };
2262
2230
  }
2263
- function extractSequenceItemCredit(activityState) {
2264
- if (activityState.attempts.length === 0) {
2265
- return [{ id: activityState.id, score: 0 }];
2231
+ function extractSequenceItemCredit(activityState, nPrevInShuffleOrder = 0) {
2232
+ if (activityState.attemptNumber === 0) {
2233
+ let nPrev = nPrevInShuffleOrder;
2234
+ return activityState.allChildren.flatMap((state) => {
2235
+ const next = extractActivityItemCredit(state, nPrev);
2236
+ nPrev += next.length;
2237
+ return next;
2238
+ });
2266
2239
  } else {
2267
- const latestAttempt = activityState.attempts[activityState.attempts.length - 1];
2268
- return latestAttempt.activities.flatMap(
2269
- (state) => extractActivityItemCredit(state)
2270
- );
2240
+ let nPrev = nPrevInShuffleOrder;
2241
+ const inShuffledOrder = activityState.orderedChildren.map((state) => {
2242
+ const next = extractActivityItemCredit(state, nPrev);
2243
+ nPrev += next.length;
2244
+ return { childId: state.id, items: next };
2245
+ });
2246
+ const inOriginalOrder = activityState.allChildren.flatMap((state) => {
2247
+ const childResults = inShuffledOrder.find(
2248
+ (obj) => obj.childId === state.id
2249
+ );
2250
+ if (!childResults) {
2251
+ throw Error("Unreachable");
2252
+ }
2253
+ return childResults.items;
2254
+ });
2255
+ return inOriginalOrder;
2271
2256
  }
2272
2257
  }
2273
- function pruneSequenceStateForSave(activityState, clearDoenetState) {
2258
+ function pruneSequenceStateForSave(activityState) {
2274
2259
  const { source: _source, ...newState } = { ...activityState };
2275
- const latestChildStates = newState.latestChildStates.map(
2276
- (child) => pruneActivityStateForSave(child, true)
2260
+ const allChildren2 = newState.allChildren.map(
2261
+ (child) => pruneActivityStateForSave(child)
2277
2262
  );
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 };
2263
+ const orderedChildren = newState.orderedChildren.map(
2264
+ (child) => pruneActivityStateForSave(child)
2265
+ );
2266
+ return { ...newState, allChildren: allChildren2, orderedChildren };
2289
2267
  }
2290
2268
  function addSourceToSequenceState(activityState, source) {
2291
- const latestChildStates = activityState.latestChildStates.map((child) => {
2269
+ const allChildren2 = activityState.allChildren.map((child) => {
2270
+ const idx = source.items.findIndex(
2271
+ (src) => src.id === extractSourceId(child.id)
2272
+ );
2273
+ return addSourceToActivityState(child, source.items[idx]);
2274
+ });
2275
+ const orderedChildren = activityState.orderedChildren.map((child) => {
2292
2276
  const idx = source.items.findIndex(
2293
2277
  (src) => src.id === extractSourceId(child.id)
2294
2278
  );
2295
2279
  return addSourceToActivityState(child, source.items[idx]);
2296
2280
  });
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
2281
  return {
2307
2282
  ...activityState,
2308
2283
  source,
2309
- latestChildStates,
2310
- attempts
2284
+ allChildren: allChildren2,
2285
+ orderedChildren
2311
2286
  };
2312
2287
  }
2313
2288
  function calcNumVariantsSequence(source, numActivityVariants) {
@@ -2323,6 +2298,14 @@ function calcNumVariantsSequence(source, numActivityVariants) {
2323
2298
  }
2324
2299
  return numVariants;
2325
2300
  }
2301
+ function getNumItemsInSequence(source) {
2302
+ const numDocumentsForEachItem = source.items.map(getNumItems);
2303
+ const totalNumDocuments = numDocumentsForEachItem.reduce(
2304
+ (a, c2) => a + c2,
2305
+ 0
2306
+ );
2307
+ return totalNumDocuments;
2308
+ }
2326
2309
  function commonjsRequire$1(path) {
2327
2310
  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
2311
  }
@@ -3123,6 +3106,13 @@ function isActivitySource(obj) {
3123
3106
  function isActivityState(obj) {
3124
3107
  return isSingleDocState(obj) || isSelectState(obj) || isSequenceState(obj);
3125
3108
  }
3109
+ function isActivityAndDoenetState(obj) {
3110
+ const typedObj = obj;
3111
+ return (
3112
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
3113
+ 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)
3114
+ );
3115
+ }
3126
3116
  function isActivityStateNoSource(obj) {
3127
3117
  return isSingleDocStateNoSource(obj) || isSelectStateNoSource(obj) || isSequenceStateNoSource(obj);
3128
3118
  }
@@ -3130,7 +3120,9 @@ function isExportedActivityState(obj) {
3130
3120
  const typedObj = obj;
3131
3121
  return (
3132
3122
  // 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")
3123
+ typedObj !== null && typeof typedObj === "object" && isActivityStateNoSource(typedObj.activityState) && Array.isArray(typedObj.doenetStates) && Array.isArray(typedObj.itemAttemptNumbers) && typedObj.itemAttemptNumbers.every(
3124
+ (x2) => Number.isInteger(x2) && x2 > 0
3125
+ ) && typeof typedObj.sourceHash === "string"
3134
3126
  );
3135
3127
  }
3136
3128
  function initializeActivityState({
@@ -3170,13 +3162,29 @@ function initializeActivityState({
3170
3162
  }
3171
3163
  throw Error("Invalid activity type");
3172
3164
  }
3165
+ function initializeActivityAndDoenetState({
3166
+ source,
3167
+ variant,
3168
+ parentId,
3169
+ numActivityVariants,
3170
+ restrictToVariantSlice
3171
+ }) {
3172
+ const activityState = initializeActivityState({
3173
+ source,
3174
+ variant,
3175
+ parentId,
3176
+ numActivityVariants,
3177
+ restrictToVariantSlice
3178
+ });
3179
+ const numItems = getNumItems(source);
3180
+ const itemAttemptNumbers = Array(numItems).fill(1);
3181
+ return { activityState, doenetStates: [], itemAttemptNumbers };
3182
+ }
3173
3183
  function generateNewActivityAttempt({
3174
3184
  state,
3175
3185
  numActivityVariants,
3176
3186
  initialQuestionCounter,
3177
- questionCounts,
3178
- parentAttempt,
3179
- resetCredit = false
3187
+ parentAttempt
3180
3188
  }) {
3181
3189
  switch (state.type) {
3182
3190
  case "singleDoc": {
@@ -3184,9 +3192,7 @@ function generateNewActivityAttempt({
3184
3192
  state,
3185
3193
  numActivityVariants,
3186
3194
  initialQuestionCounter,
3187
- questionCounts,
3188
- parentAttempt,
3189
- resetCredit
3195
+ parentAttempt
3190
3196
  });
3191
3197
  }
3192
3198
  case "select": {
@@ -3194,9 +3200,7 @@ function generateNewActivityAttempt({
3194
3200
  state,
3195
3201
  numActivityVariants,
3196
3202
  initialQuestionCounter,
3197
- questionCounts,
3198
- parentAttempt,
3199
- resetCredit
3203
+ parentAttempt
3200
3204
  });
3201
3205
  }
3202
3206
  case "sequence": {
@@ -3204,59 +3208,50 @@ function generateNewActivityAttempt({
3204
3208
  state,
3205
3209
  numActivityVariants,
3206
3210
  initialQuestionCounter,
3207
- questionCounts,
3208
- parentAttempt,
3209
- resetCredit
3211
+ parentAttempt
3210
3212
  });
3211
3213
  }
3212
3214
  }
3213
3215
  throw Error("Invalid activity type");
3214
3216
  }
3215
- function generateNewSubActivityAttempt({
3216
- id: id2,
3217
+ function generateNewSingleDocSubAttempt({
3218
+ singleDocId,
3217
3219
  state,
3218
3220
  numActivityVariants,
3219
- initialQuestionCounter,
3220
- questionCounts,
3221
- resetCredit = false
3221
+ initialQuestionCounter
3222
3222
  }) {
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;
3223
+ if (singleDocId === state.id) {
3224
+ throw Error(
3225
+ "Should not call generateSingleDocSubActivityAttempt on entire activity"
3226
+ );
3233
3227
  }
3234
3228
  const allStates = gatherStates(state);
3235
- const subActivityState = allStates[id2];
3236
- if (subActivityState.parentId === null) {
3229
+ const singleDocActivityState = allStates[singleDocId];
3230
+ if (singleDocActivityState.type !== "singleDoc") {
3231
+ throw Error(
3232
+ "generateNewSingleDocSubAttempt implemented only for single documents"
3233
+ );
3234
+ }
3235
+ if (singleDocActivityState.parentId === null) {
3237
3236
  throw Error("Lower lever should have parent");
3238
3237
  }
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;
3238
+ const parentState = allStates[singleDocActivityState.parentId];
3239
+ if (parentState.type === "select" && parentState.allChildren.every((child) => child.type === "singleDoc")) {
3240
+ const grandParentAttempt = parentState.parentId ? allStates[parentState.parentId].attemptNumber : 1;
3244
3241
  let newParentState;
3245
3242
  if (parentState.source.numToSelect > 1) {
3246
3243
  ({ state: newParentState } = generateNewSingleDocAttemptForMultiSelect({
3247
3244
  state: parentState,
3248
3245
  numActivityVariants,
3249
3246
  initialQuestionCounter,
3250
- questionCounts,
3251
3247
  parentAttempt: grandParentAttempt,
3252
- childId: id2
3248
+ childId: singleDocId
3253
3249
  }));
3254
3250
  } else {
3255
3251
  ({ state: newParentState } = generateNewActivityAttempt({
3256
3252
  state: parentState,
3257
3253
  numActivityVariants,
3258
3254
  initialQuestionCounter,
3259
- questionCounts,
3260
3255
  parentAttempt: grandParentAttempt
3261
3256
  }));
3262
3257
  }
@@ -3267,42 +3262,47 @@ function generateNewSubActivityAttempt({
3267
3262
  });
3268
3263
  } else {
3269
3264
  const { state: newSubActivityState } = generateNewActivityAttempt({
3270
- state: allStates[id2],
3265
+ state: allStates[singleDocId],
3271
3266
  numActivityVariants,
3272
3267
  initialQuestionCounter,
3273
- questionCounts,
3274
- parentAttempt: parentState.attempts.length
3268
+ parentAttempt: parentState.attemptNumber
3275
3269
  });
3276
- allStates[id2] = newSubActivityState;
3270
+ allStates[singleDocId] = newSubActivityState;
3277
3271
  return propagateStateChangeToRoot({
3278
3272
  allStates,
3279
- id: id2
3273
+ id: singleDocId
3280
3274
  });
3281
3275
  }
3282
3276
  }
3283
- function extractActivityItemCredit(activityState) {
3277
+ function extractActivityItemCredit(activityState, nPrevInShuffleOrder = 0) {
3284
3278
  switch (activityState.type) {
3285
3279
  case "singleDoc": {
3286
- return extractSingleDocItemCredit(activityState);
3280
+ return extractSingleDocItemCredit(
3281
+ activityState,
3282
+ nPrevInShuffleOrder
3283
+ );
3287
3284
  }
3288
3285
  case "select": {
3289
- return extractSelectItemCredit(activityState);
3286
+ return extractSelectItemCredit(activityState, nPrevInShuffleOrder);
3290
3287
  }
3291
3288
  case "sequence": {
3292
- return extractSequenceItemCredit(activityState);
3289
+ return extractSequenceItemCredit(
3290
+ activityState,
3291
+ nPrevInShuffleOrder
3292
+ );
3293
3293
  }
3294
3294
  }
3295
3295
  }
3296
- function pruneActivityStateForSave(activityState, clearDoenetState = false) {
3296
+ function pruneActivityStateForSave(activityState) {
3297
3297
  switch (activityState.type) {
3298
3298
  case "singleDoc": {
3299
- return pruneSingleDocStateForSave(activityState, clearDoenetState);
3299
+ return pruneSingleDocStateForSave(activityState);
3300
3300
  }
3301
3301
  case "select": {
3302
- return pruneSelectStateForSave(activityState, clearDoenetState);
3302
+ return pruneSelectStateForSave(activityState);
3303
3303
  }
3304
3304
  case "sequence": {
3305
- return pruneSequenceStateForSave(activityState, clearDoenetState);
3305
+ return pruneSequenceStateForSave(activityState);
3306
3306
  }
3307
3307
  }
3308
3308
  }
@@ -3338,12 +3338,12 @@ function getItemSequence(state) {
3338
3338
  if (state.type === "singleDoc") {
3339
3339
  return [state.id];
3340
3340
  } else {
3341
- const numAttempts = state.attempts.length;
3341
+ const numAttempts = state.attemptNumber;
3342
3342
  if (numAttempts === 0) {
3343
- if (state.latestChildStates.length === 0) {
3343
+ if (state.allChildren.length === 0) {
3344
3344
  return [];
3345
3345
  } else {
3346
- const prelimResult = state.latestChildStates.flatMap(
3346
+ const prelimResult = state.allChildren.flatMap(
3347
3347
  (a) => getItemSequence(a)
3348
3348
  );
3349
3349
  if (state.type === "sequence") {
@@ -3353,9 +3353,11 @@ function getItemSequence(state) {
3353
3353
  }
3354
3354
  }
3355
3355
  }
3356
- return state.attempts[numAttempts - 1].activities.flatMap(
3357
- (a) => getItemSequence(a)
3358
- );
3356
+ if (state.type === "sequence") {
3357
+ return state.orderedChildren.flatMap((a) => getItemSequence(a));
3358
+ } else {
3359
+ return state.selectedChildren.flatMap((a) => getItemSequence(a));
3360
+ }
3359
3361
  }
3360
3362
  }
3361
3363
  function calcNumVariants(source, numActivityVariants) {
@@ -3380,6 +3382,20 @@ function calcNumVariantsFromState(state, numActivityVariants) {
3380
3382
  }
3381
3383
  return numVariants;
3382
3384
  }
3385
+ function getNumItems(source) {
3386
+ switch (source.type) {
3387
+ case "singleDoc": {
3388
+ return 1;
3389
+ }
3390
+ case "select": {
3391
+ return getNumItemsInSelect(source);
3392
+ }
3393
+ case "sequence": {
3394
+ return getNumItemsInSequence(source);
3395
+ }
3396
+ }
3397
+ throw Error("Invalid activity type");
3398
+ }
3383
3399
  function validateIds(source) {
3384
3400
  if (source.id.includes("|")) {
3385
3401
  throw Error(`Id "${source.id}" contains a "|".`);
@@ -3398,27 +3414,22 @@ function validateIds(source) {
3398
3414
  function gatherDocumentStructure(source) {
3399
3415
  if (source.type === "singleDoc") {
3400
3416
  return {
3401
- numActivityVariants: { [source.id]: source.numVariants ?? 1 },
3402
- questionCounts: {
3403
- [source.id]: source.baseComponentCounts ? (source.baseComponentCounts.question ?? 0) + (source.baseComponentCounts.problem ?? 0) + (source.baseComponentCounts.exercise ?? 0) : 1
3404
- }
3417
+ numActivityVariants: { [source.id]: source.numVariants ?? 1 }
3405
3418
  };
3406
3419
  } else {
3407
3420
  const numActivityVariants = {};
3408
- const questionCounts = {};
3409
3421
  for (const item of source.items) {
3410
3422
  const res = gatherDocumentStructure(item);
3411
3423
  Object.assign(numActivityVariants, res.numActivityVariants);
3412
- Object.assign(questionCounts, res.questionCounts);
3413
3424
  }
3414
- return { numActivityVariants, questionCounts };
3425
+ return { numActivityVariants };
3415
3426
  }
3416
3427
  }
3417
3428
  function validateStateAndSource(state, source) {
3418
3429
  if (!isExportedActivityState(state) || !isActivitySource(source)) {
3419
3430
  return false;
3420
3431
  }
3421
- const sourceHash = hash(source);
3432
+ const sourceHash = createSourceHash(source);
3422
3433
  return state.sourceHash === sourceHash;
3423
3434
  }
3424
3435
  function gatherStates(state) {
@@ -3426,7 +3437,7 @@ function gatherStates(state) {
3426
3437
  [state.id]: state
3427
3438
  };
3428
3439
  if (state.type !== "singleDoc") {
3429
- for (const child of state.latestChildStates) {
3440
+ for (const child of state.allChildren) {
3430
3441
  Object.assign(allStates, gatherStates(child));
3431
3442
  }
3432
3443
  }
@@ -3446,31 +3457,25 @@ function propagateStateChangeToRoot({
3446
3457
  if (newParentState.type === "singleDoc") {
3447
3458
  throw Error("Single doc activity cannot be a parent");
3448
3459
  }
3449
- const childIdx = newParentState.latestChildStates.map((child) => child.id).indexOf(id2);
3460
+ const childIdx = newParentState.allChildren.map((child) => child.id).indexOf(id2);
3450
3461
  if (childIdx === -1) {
3451
3462
  throw Error("Something went wrong as parent didn't have child.");
3452
3463
  } else {
3453
- newParentState.latestChildStates = [
3454
- ...newParentState.latestChildStates
3455
- ];
3456
- newParentState.latestChildStates[childIdx] = activityState;
3464
+ newParentState.allChildren = [...newParentState.allChildren];
3465
+ newParentState.allChildren[childIdx] = activityState;
3457
3466
  }
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);
3467
+ const childActivities = newParentState.type === "sequence" ? [...newParentState.orderedChildren] : [...newParentState.selectedChildren];
3468
+ const childIdx2 = childActivities.map((child) => child.id).indexOf(id2);
3464
3469
  if (childIdx2 === -1) {
3465
3470
  throw Error(
3466
3471
  "Something went wrong as parent didn't have child in last attempt."
3467
3472
  );
3468
3473
  }
3469
- lastAttempt.activities = [...lastAttempt.activities];
3470
- lastAttempt.activities[childIdx2] = activityState;
3471
- let credit;
3474
+ childActivities[childIdx2] = activityState;
3475
+ let creditAchieved;
3472
3476
  if (newParentState.type === "sequence") {
3473
- const nonDescriptions = newParentState.latestChildStates.filter(
3477
+ newParentState.orderedChildren = childActivities;
3478
+ const nonDescriptions = newParentState.allChildren.filter(
3474
3479
  (activityState2) => activityState2.type !== "singleDoc" || !activityState2.source.isDescription
3475
3480
  );
3476
3481
  let creditWeights = [...newParentState.source.creditWeights ?? []];
@@ -3484,23 +3489,36 @@ function propagateStateChangeToRoot({
3484
3489
  creditWeights = creditWeights.slice(0, nonDescriptions.length);
3485
3490
  const totWeights = creditWeights.reduce((a, c2) => a + c2);
3486
3491
  creditWeights = creditWeights.map((w2) => w2 / totWeights);
3487
- credit = nonDescriptions.reduce(
3492
+ creditAchieved = nonDescriptions.reduce(
3488
3493
  (a, c2, i) => a + c2.creditAchieved * creditWeights[i],
3489
3494
  0
3490
3495
  );
3491
3496
  } else {
3492
- credit = lastAttempt.activities.reduce((a, c2) => a + c2.creditAchieved, 0) / lastAttempt.activities.length;
3497
+ newParentState.selectedChildren = childActivities;
3498
+ creditAchieved = childActivities.reduce((a, c2) => a + c2.creditAchieved, 0) / childActivities.length;
3493
3499
  }
3494
- lastAttempt.creditAchieved = Math.max(lastAttempt.creditAchieved, credit);
3495
- newParentState.creditAchieved = Math.max(
3496
- newParentState.creditAchieved,
3497
- credit
3498
- );
3500
+ newParentState.creditAchieved = creditAchieved;
3499
3501
  return propagateStateChangeToRoot({
3500
3502
  allStates,
3501
3503
  id: newParentState.id
3502
3504
  });
3503
3505
  }
3506
+ function removeVersionFromSource(source) {
3507
+ if (source.type === "singleDoc") {
3508
+ return {
3509
+ ...source,
3510
+ version: ""
3511
+ };
3512
+ } else {
3513
+ return {
3514
+ ...source,
3515
+ items: source.items.map(removeVersionFromSource)
3516
+ };
3517
+ }
3518
+ }
3519
+ function createSourceHash(source) {
3520
+ return hash(removeVersionFromSource(source));
3521
+ }
3504
3522
  function isSingleDocReportStateMessage(obj) {
3505
3523
  const typeObj = obj;
3506
3524
  return (
@@ -3508,6 +3526,13 @@ function isSingleDocReportStateMessage(obj) {
3508
3526
  typeObj !== null && typeof typeObj === "object" && typeof typeObj.activityId === "string" && typeof typeObj.docId === "string" && typeof typeObj.score === "number"
3509
3527
  );
3510
3528
  }
3529
+ function isRestrictToVariantSlice(obj) {
3530
+ const typeObj = obj;
3531
+ return (
3532
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
3533
+ typeObj !== null && typeof typeObj === "object" && typeof typeObj.idx === "number" && typeof typeObj.numSlices === "number"
3534
+ );
3535
+ }
3511
3536
  const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
3512
3537
  let nanoid = (size2 = 21) => {
3513
3538
  let id2 = "";
@@ -3653,14 +3678,17 @@ function MdError(props) {
3653
3678
  function SelectActivity({
3654
3679
  flags,
3655
3680
  baseId,
3681
+ maxAttemptsAllowed,
3656
3682
  forceDisable = false,
3657
3683
  forceShowCorrectness = false,
3658
3684
  forceShowSolution = false,
3659
3685
  forceUnsuppressCheckwork = false,
3660
3686
  linkSettings,
3661
3687
  darkMode = "light",
3662
- showAnswerTitles = false,
3688
+ showAnswerResponseMenu = false,
3689
+ answerResponseCountsByItem = [],
3663
3690
  state,
3691
+ doenetStates,
3664
3692
  reportScoreAndStateCallback,
3665
3693
  checkRender,
3666
3694
  checkHidden,
@@ -3668,66 +3696,64 @@ function SelectActivity({
3668
3696
  generateNewItemAttempt,
3669
3697
  hasRenderedCallback,
3670
3698
  reportVisibility = false,
3671
- reportVisibilityCallback
3699
+ reportVisibilityCallback,
3700
+ itemAttemptNumbers,
3701
+ itemSequence,
3702
+ itemWord
3672
3703
  }) {
3673
- const latestAttempt = state.attempts.length > 0 ? state.attempts[state.attempts.length - 1] : null;
3674
3704
  const selectedActivities = [];
3675
3705
  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
- }
3706
+ for (const activity of state.selectedChildren) {
3707
+ selectedActivities.push(
3708
+ /* @__PURE__ */ jsxRuntimeExports$1.jsx(
3709
+ Activity,
3710
+ {
3711
+ state: activity,
3712
+ doenetStates,
3713
+ flags,
3714
+ baseId,
3715
+ maxAttemptsAllowed,
3716
+ forceDisable,
3717
+ forceShowCorrectness,
3718
+ forceShowSolution,
3719
+ forceUnsuppressCheckwork,
3720
+ linkSettings,
3721
+ darkMode,
3722
+ showAnswerResponseMenu,
3723
+ answerResponseCountsByItem,
3724
+ reportScoreAndStateCallback,
3725
+ checkRender,
3726
+ checkHidden,
3727
+ allowItemAttemptButtons,
3728
+ generateNewItemAttempt,
3729
+ hasRenderedCallback,
3730
+ reportVisibility,
3731
+ reportVisibilityCallback,
3732
+ itemAttemptNumbers,
3733
+ itemSequence,
3734
+ itemWord
3735
+ },
3736
+ activity.id
3737
+ )
3738
+ );
3739
+ selectedIds.push(activity.id);
3706
3740
  }
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
- );
3741
+ return /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { hidden: !checkRender(state), children: /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { children: selectedActivities }) }, state.attemptNumber);
3719
3742
  }
3720
3743
  function SequenceActivity({
3721
3744
  flags,
3722
3745
  baseId,
3746
+ maxAttemptsAllowed,
3723
3747
  forceDisable = false,
3724
3748
  forceShowCorrectness = false,
3725
3749
  forceShowSolution = false,
3726
3750
  forceUnsuppressCheckwork = false,
3727
3751
  linkSettings,
3728
3752
  darkMode = "light",
3729
- showAnswerTitles = false,
3753
+ showAnswerResponseMenu = false,
3754
+ answerResponseCountsByItem = [],
3730
3755
  state,
3756
+ doenetStates,
3731
3757
  reportScoreAndStateCallback,
3732
3758
  checkRender,
3733
3759
  checkHidden,
@@ -3735,41 +3761,47 @@ function SequenceActivity({
3735
3761
  generateNewItemAttempt,
3736
3762
  hasRenderedCallback,
3737
3763
  reportVisibility = false,
3738
- reportVisibilityCallback
3764
+ reportVisibilityCallback,
3765
+ itemAttemptNumbers,
3766
+ itemSequence,
3767
+ itemWord
3739
3768
  }) {
3740
- const latestAttempt = state.attempts.length > 0 ? state.attempts[state.attempts.length - 1] : null;
3741
3769
  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
- }
3770
+ for (const activity of state.orderedChildren) {
3771
+ activityList.push(
3772
+ /* @__PURE__ */ jsxRuntimeExports$1.jsx(
3773
+ Activity,
3774
+ {
3775
+ state: activity,
3776
+ doenetStates,
3777
+ flags,
3778
+ baseId,
3779
+ maxAttemptsAllowed,
3780
+ forceDisable,
3781
+ forceShowCorrectness,
3782
+ forceShowSolution,
3783
+ forceUnsuppressCheckwork,
3784
+ linkSettings,
3785
+ darkMode,
3786
+ showAnswerResponseMenu,
3787
+ answerResponseCountsByItem,
3788
+ reportScoreAndStateCallback,
3789
+ checkRender,
3790
+ checkHidden,
3791
+ allowItemAttemptButtons,
3792
+ generateNewItemAttempt,
3793
+ hasRenderedCallback,
3794
+ reportVisibility,
3795
+ reportVisibilityCallback,
3796
+ itemAttemptNumbers,
3797
+ itemSequence,
3798
+ itemWord
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-alpha33";
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,25 @@ function SingleDocActivity({
53393
53428
  generateNewItemAttempt,
53394
53429
  hasRenderedCallback,
53395
53430
  reportVisibility = false,
53396
- reportVisibilityCallback
53431
+ reportVisibilityCallback,
53432
+ itemAttemptNumbers,
53433
+ itemSequence,
53434
+ itemWord
53397
53435
  }) {
53398
53436
  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);
53437
+ const [attemptNumber, setAttemptNumber] = useState$3(state.attemptNumber);
53401
53438
  const [initialDoenetState, setInitialDoenetState] = useState$3(
53402
- latestAttempt ? (
53403
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
53404
- latestAttempt.doenetState
53405
- ) : null
53439
+ state.doenetStateIdx === null ? null : doenetStates[state.doenetStateIdx] ?? null
53406
53440
  );
53407
53441
  const [requestedVariantIndex, setRequestedVariantIndex] = useState$3(
53408
- latestAttempt ? latestAttempt.variant : state.initialVariant
53442
+ state.currentVariant
53409
53443
  );
53410
53444
  const ref = useRef$6(null);
53445
+ const itemIdx = useMemo$4(
53446
+ () => itemSequence.indexOf(state.id),
53447
+ [itemSequence, state.id]
53448
+ );
53449
+ const itemAttemptNumber = itemAttemptNumbers[itemIdx];
53411
53450
  useEffect$5(() => {
53412
53451
  if (reportVisibility && ref.current) {
53413
53452
  const observer = new IntersectionObserver(
@@ -53422,27 +53461,24 @@ function SingleDocActivity({
53422
53461
  };
53423
53462
  }
53424
53463
  }, [reportVisibility, ref, reportVisibilityCallback, state.id]);
53425
- if (state.attempts.length !== attemptNumber) {
53426
- setAttemptNumber(state.attempts.length);
53464
+ if (state.attemptNumber !== attemptNumber) {
53465
+ setAttemptNumber(state.attemptNumber);
53427
53466
  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
53467
+ state.doenetStateIdx === null ? null : doenetStates[state.doenetStateIdx] ?? null
53435
53468
  );
53469
+ setRequestedVariantIndex(state.currentVariant);
53436
53470
  }
53437
- const initialCounters = latestAttempt ? {
53438
- question: latestAttempt.initialQuestionCounter,
53439
- problem: latestAttempt.initialQuestionCounter,
53440
- exercise: latestAttempt.initialQuestionCounter
53441
- } : void 0;
53471
+ const initialCounters = {
53472
+ question: state.initialQuestionCounter,
53473
+ problem: state.initialQuestionCounter,
53474
+ exercise: state.initialQuestionCounter
53475
+ };
53442
53476
  const source = state.source;
53443
- const showAttemptButton = allowItemAttemptButtons && generateNewItemAttempt !== void 0 && !source.isDescription;
53477
+ const showAttemptButton = allowItemAttemptButtons && generateNewItemAttempt !== void 0 && !source.isDescription && maxAttemptsAllowed !== 1;
53444
53478
  const render3 = checkRender(state);
53445
53479
  const hidden = checkHidden(state);
53480
+ const newAttemptsLeft = Math.max(maxAttemptsAllowed - itemAttemptNumber, 0);
53481
+ const attemptButtonDisabled = maxAttemptsAllowed > 0 && newAttemptsLeft <= 0;
53446
53482
  return /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { ref, children: /* @__PURE__ */ jsxRuntimeExports$1.jsxs("div", { hidden: !render3 || hidden, style: { minHeight: "100px" }, children: [
53447
53483
  /* @__PURE__ */ jsxRuntimeExports$1.jsx(
53448
53484
  DoenetViewer,
@@ -53461,7 +53497,8 @@ function SingleDocActivity({
53461
53497
  forceUnsuppressCheckwork,
53462
53498
  linkSettings,
53463
53499
  darkMode,
53464
- showAnswerTitles,
53500
+ showAnswerResponseMenu,
53501
+ answerResponseCounts: answerResponseCountsByItem[itemIdx],
53465
53502
  addVirtualKeyboard: false,
53466
53503
  initialState: initialDoenetState,
53467
53504
  initializeCounters: initialCounters,
@@ -53471,25 +53508,34 @@ function SingleDocActivity({
53471
53508
  hasRenderedCallback(state.id);
53472
53509
  }
53473
53510
  },
53474
- state.attempts.length
53511
+ state.attemptNumber
53475
53512
  ),
53476
- showAttemptButton ? /* @__PURE__ */ jsxRuntimeExports$1.jsx(
53513
+ showAttemptButton ? /* @__PURE__ */ jsxRuntimeExports$1.jsxs(
53477
53514
  "button",
53478
53515
  {
53479
53516
  hidden: !rendered,
53480
53517
  onClick: () => {
53481
53518
  generateNewItemAttempt(
53482
53519
  state.id,
53483
- (latestAttempt == null ? void 0 : latestAttempt.initialQuestionCounter) ?? 1
53520
+ state.initialQuestionCounter
53484
53521
  );
53485
53522
  },
53523
+ disabled: attemptButtonDisabled,
53486
53524
  style: {
53487
53525
  marginLeft: "20px",
53488
- backgroundColor: "lightgray",
53526
+ backgroundColor: "rgb(237, 242, 247)",
53527
+ opacity: attemptButtonDisabled ? 0.4 : "inherit",
53489
53528
  borderRadius: "10px",
53490
- padding: "5px 20px"
53529
+ padding: "5px 20px",
53530
+ cursor: attemptButtonDisabled ? "not-allowed" : "pointer"
53491
53531
  },
53492
- children: "New item attempt"
53532
+ children: [
53533
+ "New ",
53534
+ itemWord,
53535
+ " attempt",
53536
+ " ",
53537
+ maxAttemptsAllowed > 0 ? `(${newAttemptsLeft.toString()} left)` : null
53538
+ ]
53493
53539
  }
53494
53540
  ) : null
53495
53541
  ] }) });
@@ -53497,14 +53543,17 @@ function SingleDocActivity({
53497
53543
  function Activity({
53498
53544
  flags,
53499
53545
  baseId,
53546
+ maxAttemptsAllowed,
53500
53547
  forceDisable = false,
53501
53548
  forceShowCorrectness = false,
53502
53549
  forceShowSolution = false,
53503
53550
  forceUnsuppressCheckwork = false,
53504
53551
  linkSettings,
53505
53552
  darkMode = "light",
53506
- showAnswerTitles = false,
53553
+ showAnswerResponseMenu = false,
53554
+ answerResponseCountsByItem = [],
53507
53555
  state,
53556
+ doenetStates,
53508
53557
  reportScoreAndStateCallback,
53509
53558
  checkRender,
53510
53559
  checkHidden,
@@ -53512,7 +53561,10 @@ function Activity({
53512
53561
  generateNewItemAttempt,
53513
53562
  hasRenderedCallback,
53514
53563
  reportVisibility = false,
53515
- reportVisibilityCallback
53564
+ reportVisibilityCallback,
53565
+ itemAttemptNumbers,
53566
+ itemSequence,
53567
+ itemWord
53516
53568
  }) {
53517
53569
  switch (state.type) {
53518
53570
  case "singleDoc": {
@@ -53521,14 +53573,17 @@ function Activity({
53521
53573
  {
53522
53574
  flags,
53523
53575
  baseId,
53576
+ maxAttemptsAllowed,
53524
53577
  forceDisable,
53525
53578
  forceShowCorrectness,
53526
53579
  forceShowSolution,
53527
53580
  forceUnsuppressCheckwork,
53528
53581
  linkSettings,
53529
53582
  darkMode,
53530
- showAnswerTitles,
53583
+ showAnswerResponseMenu,
53584
+ answerResponseCountsByItem,
53531
53585
  state,
53586
+ doenetStates,
53532
53587
  reportScoreAndStateCallback,
53533
53588
  checkRender,
53534
53589
  checkHidden,
@@ -53536,7 +53591,10 @@ function Activity({
53536
53591
  generateNewItemAttempt,
53537
53592
  hasRenderedCallback,
53538
53593
  reportVisibility,
53539
- reportVisibilityCallback
53594
+ reportVisibilityCallback,
53595
+ itemAttemptNumbers,
53596
+ itemSequence,
53597
+ itemWord
53540
53598
  }
53541
53599
  );
53542
53600
  }
@@ -53546,14 +53604,17 @@ function Activity({
53546
53604
  {
53547
53605
  flags,
53548
53606
  baseId,
53607
+ maxAttemptsAllowed,
53549
53608
  forceDisable,
53550
53609
  forceShowCorrectness,
53551
53610
  forceShowSolution,
53552
53611
  forceUnsuppressCheckwork,
53553
53612
  linkSettings,
53554
53613
  darkMode,
53555
- showAnswerTitles,
53614
+ showAnswerResponseMenu,
53615
+ answerResponseCountsByItem,
53556
53616
  state,
53617
+ doenetStates,
53557
53618
  reportScoreAndStateCallback,
53558
53619
  checkRender,
53559
53620
  checkHidden,
@@ -53561,7 +53622,10 @@ function Activity({
53561
53622
  generateNewItemAttempt,
53562
53623
  hasRenderedCallback,
53563
53624
  reportVisibility,
53564
- reportVisibilityCallback
53625
+ reportVisibilityCallback,
53626
+ itemAttemptNumbers,
53627
+ itemSequence,
53628
+ itemWord
53565
53629
  }
53566
53630
  );
53567
53631
  }
@@ -53571,14 +53635,17 @@ function Activity({
53571
53635
  {
53572
53636
  flags,
53573
53637
  baseId,
53638
+ maxAttemptsAllowed,
53574
53639
  forceDisable,
53575
53640
  forceShowCorrectness,
53576
53641
  forceShowSolution,
53577
53642
  forceUnsuppressCheckwork,
53578
53643
  linkSettings,
53579
53644
  darkMode,
53580
- showAnswerTitles,
53645
+ showAnswerResponseMenu,
53646
+ answerResponseCountsByItem,
53581
53647
  state,
53648
+ doenetStates,
53582
53649
  reportScoreAndStateCallback,
53583
53650
  checkRender,
53584
53651
  checkHidden,
@@ -53586,155 +53653,181 @@ function Activity({
53586
53653
  generateNewItemAttempt,
53587
53654
  hasRenderedCallback,
53588
53655
  reportVisibility,
53589
- reportVisibilityCallback
53656
+ reportVisibilityCallback,
53657
+ itemAttemptNumbers,
53658
+ itemSequence,
53659
+ itemWord
53590
53660
  }
53591
53661
  );
53592
53662
  }
53593
53663
  }
53594
53664
  }
53595
- function activityStateReducer(state, action) {
53665
+ function activityDoenetStateReducer(state, action) {
53666
+ const activityState = state.activityState;
53596
53667
  switch (action.type) {
53597
53668
  case "initialize": {
53598
- return initializeActivityState({
53599
- source: state.source,
53600
- variant: action.variantIndex,
53601
- parentId: null,
53602
- numActivityVariants: action.numActivityVariants
53603
- });
53669
+ const numItems = getNumItems(action.source);
53670
+ return {
53671
+ activityState: initializeActivityState({
53672
+ source: action.source,
53673
+ variant: action.variantIndex,
53674
+ parentId: null,
53675
+ numActivityVariants: action.numActivityVariants
53676
+ }),
53677
+ doenetStates: [],
53678
+ itemAttemptNumbers: Array(numItems).fill(1)
53679
+ };
53604
53680
  }
53605
53681
  case "set": {
53606
- const scoreByItem = extractActivityItemCredit(action.state);
53607
53682
  if (action.allowSaveState) {
53608
- window.postMessage({
53609
- score: action.state.creditAchieved,
53610
- scoreByItem,
53683
+ const itemScores = extractActivityItemCredit(
53684
+ action.state.activityState
53685
+ );
53686
+ const message = {
53687
+ score: action.state.activityState.creditAchieved,
53688
+ itemScores,
53611
53689
  subject: "SPLICE.reportScoreByItem",
53612
53690
  activityId: action.baseId
53613
- });
53691
+ };
53692
+ window.postMessage(message);
53614
53693
  }
53615
53694
  return action.state;
53616
53695
  }
53617
53696
  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
- });
53697
+ const { state: newActivityState } = generateNewActivityAttempt({
53698
+ state: activityState,
53699
+ numActivityVariants: action.numActivityVariants,
53700
+ initialQuestionCounter: action.initialQuestionCounter,
53701
+ parentAttempt: 1
53702
+ });
53703
+ const newItemAttemptNumbers = state.itemAttemptNumbers.map(() => 1);
53704
+ if (action.allowSaveState) {
53705
+ const itemScores = extractActivityItemCredit(newActivityState);
53706
+ const message = {
53707
+ state: {
53708
+ activityState: pruneActivityStateForSave(newActivityState),
53709
+ doenetStates: [],
53710
+ itemAttemptNumbers: newItemAttemptNumbers,
53711
+ sourceHash: action.sourceHash
53712
+ },
53713
+ score: newActivityState.creditAchieved,
53714
+ itemScores,
53715
+ subject: "SPLICE.reportScoreAndState",
53716
+ activityId: action.baseId,
53717
+ newAttempt: true
53718
+ };
53719
+ window.postMessage(message);
53639
53720
  }
53721
+ return {
53722
+ activityState: newActivityState,
53723
+ doenetStates: [],
53724
+ itemAttemptNumbers: newItemAttemptNumbers
53725
+ };
53726
+ }
53727
+ case "generateSingleDocSubActivityAttempt": {
53728
+ if (action.docId === activityState.id) {
53729
+ throw Error(
53730
+ "Should not call generateSingleDocSubActivityAttempt on entire activity"
53731
+ );
53732
+ }
53733
+ const newActivityState = generateNewSingleDocSubAttempt({
53734
+ singleDocId: action.docId,
53735
+ state: activityState,
53736
+ numActivityVariants: action.numActivityVariants,
53737
+ initialQuestionCounter: action.initialQuestionCounter
53738
+ });
53739
+ const newDoenetMLStates = [...state.doenetStates];
53740
+ newDoenetMLStates[action.doenetStateIdx] = null;
53741
+ const itemIdx = action.itemSequence.indexOf(action.docId);
53742
+ const newItemAttemptNumbers = [...state.itemAttemptNumbers];
53743
+ newItemAttemptNumbers[itemIdx]++;
53640
53744
  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
- }
53745
+ const itemScores = extractActivityItemCredit(newActivityState);
53746
+ const itemScoresOld = extractActivityItemCredit(activityState);
53747
+ const newAttemptForItem = itemScoresOld.findIndex(
53748
+ (s) => s.id === action.docId || s.docId === action.docId
53749
+ ) + 1;
53750
+ const message = {
53751
+ state: {
53752
+ activityState: pruneActivityStateForSave(newActivityState),
53753
+ doenetStates: newDoenetMLStates,
53754
+ itemAttemptNumbers: newItemAttemptNumbers,
53755
+ sourceHash: action.sourceHash
53756
+ },
53757
+ score: newActivityState.creditAchieved,
53758
+ itemScores,
53759
+ newDoenetStateIdx: action.doenetStateIdx,
53760
+ subject: "SPLICE.reportScoreAndState",
53761
+ activityId: action.baseId,
53762
+ newAttempt: true,
53763
+ newAttemptForItem
53764
+ };
53765
+ window.postMessage(message);
53665
53766
  }
53666
- return newActivityState;
53767
+ return {
53768
+ activityState: newActivityState,
53769
+ doenetStates: newDoenetMLStates,
53770
+ itemAttemptNumbers: newItemAttemptNumbers
53771
+ };
53667
53772
  }
53668
53773
  case "updateSingleState": {
53669
- const newActivityState = updateSingleDocState(action, state);
53774
+ const newActivityDoenetState = updateSingleDocState(action, state);
53670
53775
  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({
53776
+ const newActivityState = newActivityDoenetState.activityState;
53777
+ const itemScores = extractActivityItemCredit(newActivityState);
53778
+ const itemUpdated = action.itemSequence.indexOf(action.docId) + 1;
53779
+ const message = {
53679
53780
  state: {
53680
- state: pruneActivityStateForSave(
53681
- newActivityState,
53682
- false
53683
- ),
53684
- sourceHash,
53685
- onSubmission
53781
+ activityState: pruneActivityStateForSave(newActivityState),
53782
+ sourceHash: action.sourceHash,
53783
+ doenetStates: newActivityDoenetState.doenetStates,
53784
+ itemAttemptNumbers: state.itemAttemptNumbers
53686
53785
  },
53687
53786
  score: newActivityState.creditAchieved,
53688
- scoreByItem,
53787
+ itemScores,
53788
+ itemUpdated,
53789
+ newDoenetStateIdx: action.doenetStateIdx,
53689
53790
  subject: "SPLICE.reportScoreAndState",
53690
53791
  activityId: action.baseId
53691
- });
53792
+ };
53793
+ window.postMessage(message);
53692
53794
  }
53693
- return newActivityState;
53795
+ return newActivityDoenetState;
53694
53796
  }
53695
53797
  }
53696
53798
  throw Error("Invalid activity action");
53697
53799
  }
53698
- function updateSingleDocState(action, state) {
53699
- const allStates = gatherStates(state);
53700
- const newSingleDocState = allStates[action.id] = {
53701
- ...allStates[action.id]
53800
+ function updateSingleDocState(action, activityDoenetState) {
53801
+ const allStates = gatherStates(activityDoenetState.activityState);
53802
+ const newSingleDocState = allStates[action.docId] = {
53803
+ ...allStates[action.docId]
53702
53804
  };
53703
53805
  if (newSingleDocState.type !== "singleDoc") {
53704
53806
  throw Error(
53705
53807
  "Received the wrong type of activity for updateSingleDocState"
53706
53808
  );
53707
53809
  }
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;
53810
+ newSingleDocState.creditAchieved = action.creditAchieved;
53811
+ const doenetStates = [...activityDoenetState.doenetStates];
53812
+ doenetStates[action.doenetStateIdx] = action.doenetState;
53813
+ newSingleDocState.doenetStateIdx = action.doenetStateIdx;
53724
53814
  const rootActivityState = propagateStateChangeToRoot({
53725
53815
  allStates,
53726
53816
  id: newSingleDocState.id
53727
53817
  });
53728
- return rootActivityState;
53818
+ return {
53819
+ activityState: rootActivityState,
53820
+ doenetStates,
53821
+ itemAttemptNumbers: activityDoenetState.itemAttemptNumbers
53822
+ };
53729
53823
  }
53730
53824
  function Viewer({
53731
53825
  source,
53732
53826
  flags,
53733
53827
  activityId,
53734
- userId,
53735
- attemptNumber: _attemptNumber = 1,
53736
- variantIndex: initialVariantIndex,
53737
- maxAttemptsAllowed: _maxAttemptsAllowed = Infinity,
53828
+ userId = null,
53829
+ initialVariantIndex,
53830
+ maxAttemptsAllowed = 1,
53738
53831
  itemLevelAttempts = false,
53739
53832
  activityLevelAttempts = false,
53740
53833
  paginate = true,
@@ -53747,38 +53840,51 @@ function Viewer({
53747
53840
  externalVirtualKeyboardProvided: _externalVirtualKeyboardProvided = false,
53748
53841
  linkSettings,
53749
53842
  darkMode = "light",
53750
- showAnswerTitles = false,
53751
- showTitle = true
53843
+ showAnswerResponseMenu = false,
53844
+ answerResponseCountsByItem = [],
53845
+ showTitle = true,
53846
+ itemWord = "item"
53752
53847
  }) {
53753
53848
  const [errMsg, setErrMsg] = useState$3(null);
53754
53849
  const initialPass = useRef$6(true);
53755
- const { numActivityVariants, questionCounts } = useMemo$4(() => {
53850
+ const { numActivityVariants, sourceHash, numItems } = useMemo$4(() => {
53756
53851
  try {
53757
53852
  validateIds(source);
53758
- return gatherDocumentStructure(source);
53853
+ const docStructure = gatherDocumentStructure(source);
53854
+ const sourceHash2 = createSourceHash(source);
53855
+ const numItems2 = getNumItems(source);
53856
+ return { ...docStructure, sourceHash: sourceHash2, numItems: numItems2 };
53759
53857
  } catch (e2) {
53760
53858
  const message = e2 instanceof Error ? e2.message : "";
53761
53859
  setErrMsg(`Error in activity source: ${message}`);
53762
- return { numActivityVariants: {}, questionCounts: {} };
53860
+ return {
53861
+ numActivityVariants: {},
53862
+ sourceHash: "",
53863
+ numItems: 0
53864
+ };
53763
53865
  }
53764
53866
  }, [source]);
53765
- const [activityState, activityStateDispatch] = useReducer(
53766
- activityStateReducer,
53867
+ const [activityDoenetState, activityDoenetStateDispatch] = useReducer(
53868
+ activityDoenetStateReducer,
53767
53869
  {
53768
53870
  source,
53769
53871
  variant: initialVariantIndex,
53770
53872
  parentId: null,
53771
53873
  numActivityVariants
53772
53874
  },
53773
- initializeActivityState
53875
+ initializeActivityAndDoenetState
53774
53876
  );
53877
+ const activityState = activityDoenetState.activityState;
53775
53878
  const itemSequence = getItemSequence(activityState);
53776
- const numItems = itemSequence.length;
53777
53879
  const [currentItemIdx, setCurrentItemIdx] = useState$3(0);
53778
53880
  const currentItemId = itemSequence[currentItemIdx];
53779
53881
  const [itemsRendered, setItemsRendered] = useState$3([]);
53780
53882
  const [itemsToRender, setItemsToRender] = useState$3([]);
53781
53883
  const [itemsVisible, setItemsVisible] = useState$3([]);
53884
+ const [newAttemptNum, setNewAttemptNum] = useState$3(0);
53885
+ const dialogRef = useRef$6(null);
53886
+ const newItemAttemptInfo = useRef$6({ id: "", initialQuestionCounter: 0 });
53887
+ const attemptNumber = activityState.attemptNumber;
53782
53888
  function addItemToRender(id2) {
53783
53889
  if (!itemsToRender.includes(id2)) {
53784
53890
  setItemsToRender((was) => {
@@ -53815,7 +53921,7 @@ function Viewer({
53815
53921
  if (initialPass.current) {
53816
53922
  initialPass.current = false;
53817
53923
  } else {
53818
- activityStateDispatch({
53924
+ activityDoenetStateDispatch({
53819
53925
  type: "initialize",
53820
53926
  source,
53821
53927
  variantIndex: initialVariantIndex,
@@ -53827,79 +53933,85 @@ function Viewer({
53827
53933
  const listenersAdded = [];
53828
53934
  const timeoutIdsAdded = [];
53829
53935
  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,
53936
+ return new Promise(
53937
+ (resolve, reject2) => {
53938
+ const messageId = nanoid();
53939
+ window.postMessage({
53940
+ subject: "SPLICE.getState",
53941
+ messageId,
53942
+ activityId,
53943
+ userId
53944
+ });
53945
+ let waitingToLoadState = true;
53946
+ let timeoutId = -1;
53947
+ const loadStateListener = function(event) {
53948
+ if (event.origin !== window.location.origin) {
53949
+ return;
53950
+ }
53951
+ if (event.data.subject === "SPLICE.getState.response" && event.data.messageId === messageId) {
53952
+ waitingToLoadState = false;
53953
+ if (event.data.success) {
53954
+ if (event.data.loadedState) {
53955
+ const exportedState = event.data.state;
53956
+ if (isExportedActivityState(exportedState)) {
53957
+ if (validateStateAndSource(
53958
+ exportedState,
53856
53959
  source
53857
- );
53858
- resolve(state);
53960
+ )) {
53961
+ const state = addSourceToActivityState(
53962
+ exportedState.activityState,
53963
+ source
53964
+ );
53965
+ resolve({
53966
+ activityState: state,
53967
+ doenetStates: exportedState.doenetStates,
53968
+ itemAttemptNumbers: exportedState.itemAttemptNumbers
53969
+ });
53970
+ } else {
53971
+ reject2(
53972
+ Error(
53973
+ "Received state did not match source"
53974
+ )
53975
+ );
53976
+ }
53859
53977
  } else {
53860
- reject2(
53861
- Error(
53862
- "Received state did not match source"
53863
- )
53864
- );
53978
+ reject2(Error("Received invalid state"));
53865
53979
  }
53866
53980
  } else {
53867
- reject2(Error("Received invalid state"));
53981
+ resolve(null);
53868
53982
  }
53869
53983
  } else {
53870
- resolve(null);
53984
+ reject2(Error("Error loading assignment state"));
53871
53985
  }
53872
- } else {
53873
- reject2(Error("Error loading assignment state"));
53986
+ window.removeEventListener(
53987
+ "message",
53988
+ loadStateListener
53989
+ );
53990
+ clearTimeout(timeoutId);
53874
53991
  }
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
- });
53992
+ };
53993
+ window.addEventListener("message", loadStateListener);
53994
+ listenersAdded.push(loadStateListener);
53995
+ const MESSAGE_TIMEOUT = 15e3;
53996
+ timeoutId = setTimeout(() => {
53997
+ if (!waitingToLoadState) {
53998
+ return;
53999
+ }
54000
+ reject2(Error("Time out loading assignment state"));
54001
+ }, MESSAGE_TIMEOUT);
54002
+ timeoutIdsAdded.push(timeoutId);
54003
+ }
54004
+ );
53893
54005
  }
53894
54006
  function getNewActivityState() {
53895
54007
  try {
53896
- activityStateDispatch({
54008
+ activityDoenetStateDispatch({
53897
54009
  type: "generateNewActivityAttempt",
53898
54010
  numActivityVariants,
53899
54011
  initialQuestionCounter: 1,
53900
- questionCounts,
53901
54012
  allowSaveState: flags.allowSaveState,
53902
- baseId: activityId
54013
+ baseId: activityId,
54014
+ sourceHash
53903
54015
  });
53904
54016
  } catch (e2) {
53905
54017
  const message = e2 instanceof Error ? e2.message : "";
@@ -53908,8 +54020,8 @@ function Viewer({
53908
54020
  }
53909
54021
  if (flags.allowLoadState) {
53910
54022
  loadState().then((state) => {
53911
- if (isActivityState(state)) {
53912
- activityStateDispatch({
54023
+ if (isActivityAndDoenetState(state)) {
54024
+ activityDoenetStateDispatch({
53913
54025
  type: "set",
53914
54026
  state,
53915
54027
  allowSaveState: flags.allowSaveState,
@@ -53943,7 +54055,7 @@ function Viewer({
53943
54055
  userId,
53944
54056
  source,
53945
54057
  numActivityVariants,
53946
- questionCounts
54058
+ sourceHash
53947
54059
  ]);
53948
54060
  function clickNext() {
53949
54061
  setCurrentItemIdx((was) => Math.min(numItems - 1, was + 1));
@@ -53953,25 +54065,37 @@ function Viewer({
53953
54065
  }
53954
54066
  function reportScoreAndStateCallback(msg) {
53955
54067
  if (isSingleDocReportStateMessage(msg)) {
53956
- activityStateDispatch({
54068
+ activityDoenetStateDispatch({
53957
54069
  type: "updateSingleState",
53958
- id: msg.docId,
54070
+ docId: msg.docId,
53959
54071
  doenetState: msg.state,
54072
+ doenetStateIdx: itemSequence.indexOf(msg.docId),
54073
+ itemSequence,
53960
54074
  creditAchieved: msg.score,
53961
54075
  allowSaveState: flags.allowSaveState,
53962
- baseId: activityId
54076
+ baseId: activityId,
54077
+ sourceHash
53963
54078
  });
53964
54079
  }
53965
54080
  }
53966
- function generateNewItemAttempt(id2, initialQuestionCounter) {
53967
- activityStateDispatch({
53968
- type: "generateNewActivityAttempt",
53969
- id: id2,
54081
+ function generateNewItemAttemptPrompt(id2, initialQuestionCounter) {
54082
+ var _a;
54083
+ newItemAttemptInfo.current = { id: id2, initialQuestionCounter };
54084
+ setNewAttemptNum((itemSequence.indexOf(id2) ?? 0) + 1);
54085
+ (_a = dialogRef.current) == null ? void 0 : _a.showModal();
54086
+ }
54087
+ function generateNewItemAttempt() {
54088
+ const { id: id2, initialQuestionCounter } = newItemAttemptInfo.current;
54089
+ activityDoenetStateDispatch({
54090
+ type: "generateSingleDocSubActivityAttempt",
54091
+ docId: id2,
54092
+ doenetStateIdx: itemSequence.indexOf(id2),
54093
+ itemSequence,
53970
54094
  numActivityVariants,
53971
54095
  initialQuestionCounter,
53972
- questionCounts,
53973
54096
  allowSaveState: flags.allowSaveState,
53974
- baseId: activityId
54097
+ baseId: activityId,
54098
+ sourceHash
53975
54099
  });
53976
54100
  setItemsRendered((was) => {
53977
54101
  const idx = was.indexOf(id2);
@@ -54027,16 +54151,17 @@ function Viewer({
54027
54151
  });
54028
54152
  }
54029
54153
  function generateActivityAttempt() {
54030
- activityStateDispatch({
54154
+ setItemsRendered([]);
54155
+ setItemsToRender([]);
54156
+ setCurrentItemIdx(0);
54157
+ activityDoenetStateDispatch({
54031
54158
  type: "generateNewActivityAttempt",
54032
54159
  numActivityVariants,
54033
54160
  initialQuestionCounter: 1,
54034
- questionCounts,
54035
54161
  allowSaveState: flags.allowSaveState,
54036
- baseId: activityId
54162
+ baseId: activityId,
54163
+ sourceHash
54037
54164
  });
54038
- setItemsRendered([]);
54039
- setCurrentItemIdx(0);
54040
54165
  }
54041
54166
  if (errMsg !== null) {
54042
54167
  const errorIcon = /* @__PURE__ */ jsxRuntimeExports$1.jsx("span", { style: { fontSize: "1em", color: "#C1292E" }, children: /* @__PURE__ */ jsxRuntimeExports$1.jsx(MdError, {}) });
@@ -54078,7 +54203,77 @@ function Viewer({
54078
54203
  }
54079
54204
  }
54080
54205
  }
54206
+ const activityAttemptsLeft = Math.max(
54207
+ maxAttemptsAllowed - attemptNumber,
54208
+ 0
54209
+ );
54210
+ const newAttemptsLeft = newAttemptNum === 0 ? activityAttemptsLeft : Math.max(
54211
+ maxAttemptsAllowed - activityDoenetState.itemAttemptNumbers[newAttemptNum - 1],
54212
+ 0
54213
+ );
54214
+ const newAttemptDisabled = numItems === 0 || maxAttemptsAllowed > 0 && activityAttemptsLeft <= 0;
54081
54215
  return /* @__PURE__ */ jsxRuntimeExports$1.jsxs("div", { children: [
54216
+ /* @__PURE__ */ jsxRuntimeExports$1.jsxs("dialog", { ref: dialogRef, children: [
54217
+ /* @__PURE__ */ jsxRuntimeExports$1.jsxs("h3", { children: [
54218
+ "Create new attempt of",
54219
+ " ",
54220
+ newAttemptNum === 0 ? "the entire activity" : `${itemWord} ${newAttemptNum.toString()}`,
54221
+ "?"
54222
+ ] }),
54223
+ /* @__PURE__ */ jsxRuntimeExports$1.jsxs("p", { children: [
54224
+ "Creating a new attempt will generate",
54225
+ " ",
54226
+ newAttemptNum === 0 ? `new versions of all ${itemWord}s so that you can start again at the beginning.` : `a new version of ${itemWord} ${newAttemptNum.toString()} so that you can start that ${itemWord} again.`
54227
+ ] }),
54228
+ maxAttemptsAllowed > 0 ? /* @__PURE__ */ jsxRuntimeExports$1.jsxs("p", { children: [
54229
+ "You can create a new attempt",
54230
+ " ",
54231
+ newAttemptsLeft.toString(),
54232
+ " more time",
54233
+ newAttemptsLeft > 1 ? "s" : "",
54234
+ "."
54235
+ ] }) : null,
54236
+ /* @__PURE__ */ jsxRuntimeExports$1.jsxs("p", { style: { marginTop: "30px" }, children: [
54237
+ /* @__PURE__ */ jsxRuntimeExports$1.jsx(
54238
+ "button",
54239
+ {
54240
+ autoFocus: true,
54241
+ onClick: () => {
54242
+ var _a;
54243
+ (_a = dialogRef.current) == null ? void 0 : _a.close();
54244
+ },
54245
+ style: {
54246
+ marginLeft: "30px",
54247
+ backgroundColor: "lightgray",
54248
+ borderRadius: "10px",
54249
+ padding: "5px 20px"
54250
+ },
54251
+ children: "Cancel"
54252
+ }
54253
+ ),
54254
+ /* @__PURE__ */ jsxRuntimeExports$1.jsx(
54255
+ "button",
54256
+ {
54257
+ onClick: () => {
54258
+ var _a;
54259
+ if (newAttemptNum === 0) {
54260
+ generateActivityAttempt();
54261
+ } else {
54262
+ generateNewItemAttempt();
54263
+ }
54264
+ (_a = dialogRef.current) == null ? void 0 : _a.close();
54265
+ },
54266
+ style: {
54267
+ marginLeft: "30px",
54268
+ backgroundColor: "lightgray",
54269
+ borderRadius: "10px",
54270
+ padding: "5px 20px"
54271
+ },
54272
+ children: "Create new attempt"
54273
+ }
54274
+ )
54275
+ ] })
54276
+ ] }),
54082
54277
  showTitle ? /* @__PURE__ */ jsxRuntimeExports$1.jsx("h2", { style: { marginLeft: "20px" }, children: source.title }) : null,
54083
54278
  /* @__PURE__ */ jsxRuntimeExports$1.jsx("div", { style: { marginTop: "5px" }, children: /* @__PURE__ */ jsxRuntimeExports$1.jsxs("div", { children: [
54084
54279
  /* @__PURE__ */ jsxRuntimeExports$1.jsxs("span", { hidden: !paginate, children: [
@@ -54116,18 +54311,28 @@ function Viewer({
54116
54311
  }
54117
54312
  )
54118
54313
  ] }),
54119
- activityLevelAttempts ? /* @__PURE__ */ jsxRuntimeExports$1.jsx(
54314
+ activityLevelAttempts && maxAttemptsAllowed !== 1 ? /* @__PURE__ */ jsxRuntimeExports$1.jsxs(
54120
54315
  "button",
54121
54316
  {
54122
- onClick: generateActivityAttempt,
54123
- disabled: numItems === 0,
54317
+ onClick: () => {
54318
+ var _a;
54319
+ setNewAttemptNum(0);
54320
+ (_a = dialogRef.current) == null ? void 0 : _a.showModal();
54321
+ },
54322
+ disabled: newAttemptDisabled,
54124
54323
  style: {
54125
54324
  marginLeft: "30px",
54126
- backgroundColor: "lightgray",
54325
+ backgroundColor: "rgb(237, 242, 247)",
54326
+ opacity: newAttemptDisabled ? 0.4 : "inherit",
54127
54327
  borderRadius: "10px",
54128
- padding: "5px 20px"
54328
+ padding: "5px 20px",
54329
+ cursor: newAttemptDisabled ? "not-allowed" : "pointer"
54129
54330
  },
54130
- children: "New attempt"
54331
+ children: [
54332
+ "New attempt",
54333
+ " ",
54334
+ maxAttemptsAllowed > 0 ? `(${activityAttemptsLeft.toString()} left)` : null
54335
+ ]
54131
54336
  }
54132
54337
  ) : null
54133
54338
  ] }) }),
@@ -54144,22 +54349,28 @@ function Viewer({
54144
54349
  {
54145
54350
  flags,
54146
54351
  baseId: activityId,
54352
+ maxAttemptsAllowed,
54147
54353
  forceDisable,
54148
54354
  forceShowCorrectness,
54149
54355
  forceShowSolution,
54150
54356
  forceUnsuppressCheckwork,
54151
54357
  linkSettings,
54152
54358
  darkMode,
54153
- showAnswerTitles,
54359
+ showAnswerResponseMenu,
54360
+ answerResponseCountsByItem,
54154
54361
  state: activityState,
54362
+ doenetStates: activityDoenetState.doenetStates,
54155
54363
  reportScoreAndStateCallback,
54156
54364
  checkRender,
54157
54365
  checkHidden,
54158
54366
  allowItemAttemptButtons: itemLevelAttempts,
54159
- generateNewItemAttempt,
54367
+ generateNewItemAttempt: generateNewItemAttemptPrompt,
54160
54368
  hasRenderedCallback,
54161
54369
  reportVisibility: !paginate,
54162
- reportVisibilityCallback
54370
+ reportVisibilityCallback,
54371
+ itemAttemptNumbers: activityDoenetState.itemAttemptNumbers,
54372
+ itemSequence,
54373
+ itemWord
54163
54374
  }
54164
54375
  )
54165
54376
  ] });
@@ -54182,10 +54393,9 @@ function ActivityViewer({
54182
54393
  source,
54183
54394
  flags: specifiedFlags = {},
54184
54395
  activityId = "a",
54185
- userId,
54186
- attemptNumber = 1,
54396
+ userId = null,
54187
54397
  requestedVariantIndex,
54188
- maxAttemptsAllowed = Infinity,
54398
+ maxAttemptsAllowed = 1,
54189
54399
  itemLevelAttempts = false,
54190
54400
  activityLevelAttempts = false,
54191
54401
  paginate = true,
@@ -54198,11 +54408,13 @@ function ActivityViewer({
54198
54408
  externalVirtualKeyboardProvided = false,
54199
54409
  linkSettings,
54200
54410
  darkMode = "light",
54201
- showAnswerTitles = false,
54411
+ showAnswerResponseMenu = false,
54412
+ answerResponseCountsByItem = [],
54202
54413
  includeVariantSelector: _includeVariantSelector = false,
54203
- showTitle = true
54414
+ showTitle = true,
54415
+ itemWord = "item"
54204
54416
  }) {
54205
- const [variantIndex, setVariantIndex] = useState$3(null);
54417
+ const [initialVariantIndex, setInitialVariantIndex] = useState$3(null);
54206
54418
  const thisPropSet = {
54207
54419
  source: JSON.stringify(source),
54208
54420
  activityId,
@@ -54221,14 +54433,14 @@ function ActivityViewer({
54221
54433
  if (foundPropChange) {
54222
54434
  if (requestedVariantIndex === void 0) {
54223
54435
  const rng = rngClass((/* @__PURE__ */ new Date()).toString());
54224
- setVariantIndex(Math.floor(rng() * 1e6) + 1);
54436
+ setInitialVariantIndex(Math.floor(rng() * 1e6) + 1);
54225
54437
  } else {
54226
- setVariantIndex(
54438
+ setInitialVariantIndex(
54227
54439
  Number.isInteger(requestedVariantIndex) ? requestedVariantIndex : 1
54228
54440
  );
54229
54441
  }
54230
54442
  }
54231
- if (variantIndex === null) {
54443
+ if (initialVariantIndex === null) {
54232
54444
  return null;
54233
54445
  }
54234
54446
  return /* @__PURE__ */ jsxRuntimeExports$1.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntimeExports$1.jsx(
@@ -54238,8 +54450,7 @@ function ActivityViewer({
54238
54450
  flags,
54239
54451
  activityId,
54240
54452
  userId,
54241
- attemptNumber,
54242
- variantIndex,
54453
+ initialVariantIndex,
54243
54454
  maxAttemptsAllowed,
54244
54455
  itemLevelAttempts,
54245
54456
  activityLevelAttempts,
@@ -54253,8 +54464,10 @@ function ActivityViewer({
54253
54464
  externalVirtualKeyboardProvided,
54254
54465
  linkSettings,
54255
54466
  darkMode,
54256
- showAnswerTitles,
54257
- showTitle
54467
+ showAnswerResponseMenu,
54468
+ answerResponseCountsByItem,
54469
+ showTitle,
54470
+ itemWord
54258
54471
  }
54259
54472
  ) });
54260
54473
  }