@khanacademy/perseus 77.3.2 → 77.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +8 -7
- package/dist/es/index.js.map +1 -1
- package/dist/es/strings.js +1 -1
- package/dist/es/strings.js.map +1 -1
- package/dist/index.js +8 -7
- package/dist/index.js.map +1 -1
- package/dist/server-item-renderer.d.ts +1 -1
- package/dist/strings.d.ts +2 -0
- package/dist/strings.js +1 -1
- package/dist/strings.js.map +1 -1
- package/dist/testing/feature-flags-util.d.ts +2 -0
- package/dist/testing/item-renderer-hooks.d.ts +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/widgets/dropdown/dropdown.d.ts +2 -1
- package/dist/widgets/expression/expression.d.ts +4 -2
- package/dist/widgets/interactive-graphs/interactive-graph.d.ts +7 -4
- package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +1 -0
- package/dist/widgets/label-image/label-image.d.ts +2 -1
- package/dist/widgets/mock-widgets/mock-widget.d.ts +2 -1
- package/dist/widgets/numeric-input/numeric-input.class.d.ts +2 -1
- package/dist/widgets/numeric-input/numeric-input.d.ts +3 -2
- package/dist/widgets/table/table.d.ts +2 -1
- package/dist/widgets.d.ts +5 -0
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1459,7 +1459,7 @@ function requireJsxRuntime () {
|
|
|
1459
1459
|
|
|
1460
1460
|
var jsxRuntimeExports = requireJsxRuntime();
|
|
1461
1461
|
|
|
1462
|
-
const mockStrings={characterCount:({used,num})=>num===1?`${used} / ${num} Character`:`${used} / ${num} Characters`,closeKeypad:"close math keypad",openKeypad:"open math keypad",mathInputBox:"Math input box",removeHighlight:"Remove highlight",addHighlight:"Add highlight",hintPos:({pos})=>`Hint #${pos}`,errorRendering:({error})=>`Error rendering: ${error}`,APPROXIMATED_PI_ERROR:"Your answer is close, but you may "+"have approximated pi. Enter your "+"answer as a multiple of pi, like "+"<code>12\\ \\text{pi}</code> or "+"<code>2/3\\ \\text{pi}</code>",EMPTY_RESPONSE_ERROR:"There are still more parts of this question to answer.",EXTRA_SYMBOLS_ERROR:"We could not understand your "+"answer. Please check your answer for extra "+"text or symbols.",NEEDS_TO_BE_SIMPLFIED_ERROR:"Your answer is almost correct, "+"but it needs to be simplified.",MISSING_PERCENT_ERROR:"Your answer is almost correct, "+"but it is missing a "+"<code>\\%</code> at the end.",MULTIPLICATION_SIGN_ERROR:"I'm a computer. I only understand "+"multiplication if you use an asterisk "+"(*) as the multiplication sign.",USER_INPUT_EMPTY:"Your answer is empty.",USER_INPUT_TOO_LONG:"Please shorten your response.",WRONG_CASE_ERROR:"Your answer includes use of a variable with the wrong case.",WRONG_LETTER_ERROR:"Your answer includes a wrong variable letter.",invalidSelection:"Make sure you select something for every row.",INVALID_CHOICE_SELECTION:"Invalid choice selection",ERROR_TITLE:"Oops!",ERROR_MESSAGE:"Sorry, I don't understand that!",hints:"Hints",getAnotherHint:"Get another hint",deprecatedStandin:"Sorry, this part of the question is no longer available. 😅 Don't worry, you won't be graded on this part. Keep going!",keepTrying:"Keep trying",tryAgain:"Try again",check:"Check",correctExcited:"Correct!",nextQuestion:"Next question",skipToTitle:({title})=>`Skip to ${title}`,current:"Current",correct:"Correct",correctSelected:"Correct (selected)",incorrect:"Incorrect",incorrectSelected:"Incorrect (selected)",hideExplanation:"Hide explanation",explain:"Explain",INVALID_MESSAGE_PREFIX:"We couldn't grade your answer.",DEFAULT_INVALID_MESSAGE_1:"It looks like you left something blank or ",DEFAULT_INVALID_MESSAGE_2:"entered in an invalid answer.",integerExample:"an integer, like $6$",properExample:"a *proper* fraction, like $1/2$ or $6/10$",simplifiedProperExample:"a *simplified proper* fraction, like $3/5$",improperExample:"an *improper* fraction, like $10/7$ or $14/8$",simplifiedImproperExample:"a *simplified improper* fraction, like $7/4$",mixedExample:"a mixed number, like $1\\ 3/4$",decimalExample:"an *exact* decimal, like $0.75$",percentExample:"a percent, like $12.34\\%$",piExample:"a multiple of pi, like $12\\ \\text{pi}$ or $2/3\\ \\text{pi}$",yourAnswer:"**Your answer should be** ",yourAnswerLabel:"Your answer:",addPoints:"Click to add points",addVertices:"Click to add vertices",tapMultiple:"Tap each dot on the image to select all answers that apply.",tapSingle:"Tap each dot on the image to select an answer.",clickMultiple:"Click each dot on the image to select all answers that apply.",clickSingle:"Click each dot on the image to select an answer.",choices:"Choices:",answers:({num})=>num===1?`${num} answer`:`${num} answers`,hideAnswersToggleLabel:"Hide answer choices",moves:({num})=>num===1?`Moves: ${num}`:`Moves: ${num}`,clickTiles:"Click on the tiles to change the lights.",turnOffLights:"You must turn on all of the lights to continue.",fillAllCells:"Make sure you fill in all cells in the matrix.",molecularDrawing:({content})=>`A molecular structure drawing. SMILES notation: ${content}`,switchDirection:"Switch direction",circleOpen:"Make circle open",circleFilled:"Make circle filled",numDivisions:"Number of divisions:",divisions:({divRangeString})=>`Please make sure the number of divisions is in the range ${divRangeString}.`,dragHandles:"Drag handles to make graph",tapAddPoints:"Tap to add points",false:"False",true:"True",no:"No",yes:"Yes",chooseCorrectNum:"Please choose the correct number of answers.",notNoneOfTheAbove:"'None of the above' may not be selected when other answers are selected.",noneOfTheAbove:"None of the above",chooseNumAnswers:({numCorrect})=>`Choose ${numCorrect} answers:`,chooseAllAnswers:"Choose all answers that apply:",chooseOneAnswer:"Choose 1 answer:",choiceCheckedCorrect:({letter})=>`(Choice ${letter}, Checked, Correct)`,choiceCorrect:({letter})=>`(Choice ${letter}, Correct)`,choiceCheckedIncorrect:({letter})=>`(Choice ${letter}, Checked, Incorrect)`,choiceIncorrect:({letter})=>`(Choice ${letter}, Incorrect)`,choiceChecked:({letter})=>`(Choice ${letter}, Checked)`,choice:({letter})=>`(Choice ${letter})`,notSelected:"not selected",choicesSelected:({num})=>num===1?`${num} choice selected`:`${num} choices selected`,bringBack:"Bring back",openMenuForChoice:({letter})=>`Open menu for Choice ${letter}`,letters:"A B C D E F G H I J K L M N O P Q R S T U V W X Y Z",scrollAnswers:"Scroll Answers",scrollStart:"Scroll to view start of the content",scrollEnd:"Scroll to view the end of the content",rightArrow:"Reaction arrow pointing to the right.",dontUnderstandUnits:"I couldn't understand those units.",checkSigFigs:"Check your significant figures.",answerNumericallyIncorrect:"That answer is numerically incorrect.",checkUnits:"Check your units.",dontUnderstand:"I don't understand that",loading:"Loading...",videoTranscript:"See video transcript",somethingWrong:"Something went wrong.",videoWrapper:"Khan Academy video wrapper",mathInputTitle:"mathematics keyboard",mathInputDescription:"Use keyboard/mouse to interact with math-based input fields",sin:"sin",cos:"cos",tan:"tan",simulationLoadFail:"Sorry, this simulation cannot load.",simulationLocaleWarning:"Sorry, this simulation isn't available in your language.",selectAnAnswer:"Select an answer",srGraphInstructions:"Use the Tab key to move through the interactive elements in the graph. When an interactive element has focus, use Control + Shift + Arrows to move it.",srUnlimitedGraphInstructions:"Press Shift + Enter to interact with the graph. Use the Tab key to move through the interactive elements in the graph and access the graph Action Bar. When an interactive element has focus, use Control + Shift + Arrows to move it or use the Delete key to remove it from the graph. Use the buttons in the Action Bar to add or adjust elements within the graph.",graphKeyboardPrompt:"Press Shift + Enter to interact with the graph",addPoint:"Add Point",removePoint:"Remove Point",closePolygon:"Close shape",openPolygon:"Re-open shape",srPointAtCoordinates:({num,x,y})=>`Point ${num} at ${x} comma ${y}.`,srInteractiveElements:({elements})=>`Interactive elements: ${elements}`,srNoInteractiveElements:"No interactive elements",srCircleGraph:"A circle on a coordinate plane.",srCircleShape:({centerX,centerY})=>`Circle. The center point is at ${centerX} comma ${centerY}.`,srCircleRadiusPointRight:({radiusPointX,radiusPointY})=>`Right radius endpoint at ${radiusPointX} comma ${radiusPointY}.`,srCircleRadiusPointLeft:({radiusPointX,radiusPointY})=>`Left radius endpoint at ${radiusPointX} comma ${radiusPointY}.`,srCircleRadius:({radius})=>`Circle radius is ${radius}.`,srCircleOuterPoints:({point1X,point1Y,point2X,point2Y,point3X,point3Y,point4X,point4Y})=>`Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`,srLinearGraph:"A line on a coordinate plane.",srLinearGraphPoints:({point1X,point1Y,point2X,point2Y})=>`The line has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`,srLinearGraphSlopeIncreasing:"Its slope increases from left to right.",srLinearGraphSlopeDecreasing:"Its slope decreases from left to right.",srLinearGraphSlopeHorizontal:"Its slope is zero.",srLinearGraphSlopeVertical:"Its slope is undefined.",srLinearGraphXOnlyIntercept:({xIntercept})=>`The line crosses the X-axis at ${xIntercept} comma 0.`,srLinearGraphYOnlyIntercept:({yIntercept})=>`The line crosses the Y-axis at 0 comma ${yIntercept}.`,srLinearGraphBothIntercepts:({xIntercept,yIntercept})=>`The line crosses the X-axis at ${xIntercept} comma 0 and the Y-axis at 0 comma ${yIntercept}.`,srLinearGraphOriginIntercept:"The line crosses the X and Y axes at the graph's origin.",srLinearGrabHandle:({point1X,point1Y,point2X,point2Y})=>`Line going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`,srAngleStartingSide:({x,y})=>`Point 3, starting side at ${x} comma ${y}.`,srAngleEndingSide:({x,y})=>`Point 2, ending side at ${x} comma ${y}.`,srAngleVertexWithAngleMeasure:({x,y,angleMeasure})=>`Point 1, vertex at ${x} comma ${y}. Angle ${angleMeasure} degrees.`,srAngleGraphAriaLabel:"An angle on a coordinate plane.",srAngleGraphAriaDescription:({angleMeasure,vertexX,vertexY,startingSideX,startingSideY,endingSideX,endingSideY})=>`The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the starting side at ${startingSideX} comma ${startingSideY} and a point on the ending side at ${endingSideX} comma ${endingSideY}.`,srAngleInteractiveElements:({vertexX,vertexY,startingSideX,startingSideY,endingSideX,endingSideY})=>`An angle formed by 3 points. The vertex is at ${vertexX} comma ${vertexY}. The starting side point is at ${startingSideX} comma ${startingSideY}. The ending side point is at ${endingSideX} comma ${endingSideY}.`,srSingleSegmentGraphAriaLabel:"A line segment on a coordinate plane.",srMultipleSegmentGraphAriaLabel:({countOfSegments})=>`${countOfSegments} segments on a coordinate plane.`,srMultipleSegmentIndividualLabel:({point1X,point1Y,point2X,point2Y,indexOfSegment})=>`Segment ${indexOfSegment}: Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`,srSingleSegmentLabel:({point1X,point1Y,point2X,point2Y})=>`Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`,srSegmentLength:({length})=>`Segment length ${length} units.`,srSingleSegmentGraphEndpointAriaLabel:({endpointNumber,x,y})=>`Endpoint ${endpointNumber} at ${x} comma ${y}.`,srMultipleSegmentGraphEndpointAriaLabel:({endpointNumber,x,y,indexOfSegment})=>`Endpoint ${endpointNumber} on segment ${indexOfSegment} at ${x} comma ${y}.`,srSegmentGrabHandle:({point1X,point1Y,point2X,point2Y})=>`Segment from ${point1X} comma ${point1Y} to ${point2X} comma ${point2Y}.`,srLinearSystemGraph:"Two lines on a coordinate plane.",srLinearSystemPoints:({lineNumber,point1X,point1Y,point2X,point2Y})=>`Line ${lineNumber} has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`,srLinearSystemPoint:({lineNumber,pointSequence,x,y})=>`Point ${pointSequence} on line ${lineNumber} at ${x} comma ${y}.`,srLinearSystemGrabHandle:({lineNumber,point1X,point1Y,point2X,point2Y})=>`Line ${lineNumber} going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`,srLinearSystemIntersection:({x,y})=>`Line 1 and line 2 intersect at point ${x} comma ${y}.`,srLinearSystemParallel:"Line 1 and line 2 are parallel.",srRayGraph:"A ray on a coordinate plane.",srRayPoints:({point1X,point1Y,point2X,point2Y})=>`The endpoint is at ${point1X} comma ${point1Y} and the ray goes through point ${point2X} comma ${point2Y}.`,srRayGrabHandle:({point1X,point1Y,point2X,point2Y})=>`Ray with endpoint ${point1X} comma ${point1Y} going through point ${point2X} comma ${point2Y}.`,srRayEndpoint:({x,y})=>`Endpoint at ${x} comma ${y}.`,srRayTerminalPoint:({x,y})=>`Through point at ${x} comma ${y}.`,srVectorGraph:"A vector on a coordinate plane.",srVectorPoints:({tailX,tailY,tipX,tipY})=>`The tail is at ${tailX} comma ${tailY} and the tip is at ${tipX} comma ${tipY}.`,srVectorTipPoint:({x,y})=>`Tip point at ${x} comma ${y}.`,srVectorGrabHandle:({tailX,tailY,tipX,tipY})=>`Vector from ${tailX} comma ${tailY} to ${tipX} comma ${tipY}.`,srQuadraticGraph:"A parabola on a 4-quadrant coordinate plane.",srQuadraticFaceUp:"The parabola opens upward.",srQuadraticFaceDown:"The parabola opens downward.",srQuadraticGraphVertexOrigin:"Vertex is at the origin.",srQuadraticGraphVertexXAxis:"Vertex is on the X-axis.",srQuadraticGraphVertexYAxis:"Vertex is on the Y-axis.",srQuadraticGraphVertexQuadrant:({quadrant})=>`Vertex is in quadrant ${quadrant}.`,srQuadraticTwoXIntercepts:({intercept1,intercept2})=>`The X-intercepts are at ${intercept1} comma 0 and ${intercept2} comma 0.`,srQuadraticOneXIntercept:({intercept})=>`The X-intercept is at ${intercept} comma 0.`,srQuadraticYIntercept:({intercept})=>`The Y-intercept is at 0 comma ${intercept}.`,srQuadraticPointOrigin:({pointNumber})=>`Point ${pointNumber} on parabola at the origin.`,srQuadraticPointAxis:({pointNumber,x,y})=>`Point ${pointNumber} on parabola at ${x} comma ${y}.`,srQuadraticPointQuadrant:({pointNumber,x,y,quadrant})=>`Point ${pointNumber} on parabola in quadrant ${quadrant} at ${x} comma ${y}.`,srQuadraticInteractiveElements:({point1X,point1Y,point2X,point2Y,point3X,point3Y})=>`Parabola with points at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, and ${point3X} comma ${point3Y}.`,srPolygonGraph:"A polygon.",srPolygonGraphCoordinatePlane:"A polygon on a coordinate plane.",srPolygonGraphPointsNum:({num})=>`The polygon has ${num} points.`,srPolygonGraphPointsOne:"The polygon has 1 point.",srPolygonElementsNum:({num})=>`A polygon with ${num} points.`,srPolygonElementsOne:"A polygon with 1 point.",srPolygonPointAngleApprox:({angle})=>`Angle approximately equal to ${angle} degrees.`,srPolygonPointAngle:({angle})=>`Angle equal to ${angle} degrees.`,srPolygonSideLength:({pointNum,length})=>`A line segment, length equal to ${length} units, connects to point ${pointNum}.`,srPolygonSideLengthApprox:({pointNum,length})=>`A line segment, length approximately equal to ${length} units, connects to point ${pointNum}.`,srUnlimitedPolygonEmpty:"An empty coordinate plane.",srSinusoidGraph:"A sinusoid function on a coordinate plane.",srSinusoidRootPoint:({x,y})=>`Midline intersection at ${x} comma ${y}.`,srSinusoidMaxPoint:({x,y})=>`Maximum point at ${x} comma ${y}.`,srSinusoidMinPoint:({x,y})=>`Minimum point at ${x} comma ${y}.`,srSinusoidFlatPoint:({x,y})=>`Line through point at ${x} comma ${y}.`,srSinusoidDescription:({minValue,maxValue,cycleStart,cycleEnd})=>`The graph shows a wave with a minimum value of ${minValue} and a maximum value of ${maxValue}. The wave completes a full cycle from ${cycleStart} to ${cycleEnd}.`,srSinusoidInteractiveElements:({point1X,point1Y,point2X,point2Y})=>`Sinusoid graph with midline intersection point at ${point1X} comma ${point1Y} and extremum point at ${point2X} comma ${point2Y}.`,srExponentialGraph:"An exponential curve on a coordinate plane.",srExponentialPoint1:({x,y})=>`Point 1 at ${x} comma ${y}.`,srExponentialPoint2:({x,y})=>`Point 2 at ${x} comma ${y}.`,srExponentialDescription:({point1X,point1Y,point2X,point2Y,asymptoteY})=>`The graph shows an exponential curve passing through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y} with a horizontal asymptote at y equals ${asymptoteY}.`,srExponentialInteractiveElements:({point1X,point1Y,point2X,point2Y,asymptoteY})=>`Exponential graph with point 1 at ${point1X} comma ${point1Y}, point 2 at ${point2X} comma ${point2Y}, and horizontal asymptote at y equals ${asymptoteY}.`,srExponentialAsymptote:({asymptoteY})=>`Horizontal asymptote at y equals ${asymptoteY}. Use up and down arrow keys to move.`,srLogarithmGraph:"A logarithm function on a coordinate plane.",srLogarithmPoint1:({x,y})=>`Point 1 at ${x} comma ${y}.`,srLogarithmPoint2:({x,y})=>`Point 2 at ${x} comma ${y}.`,srLogarithmDescription:({point1X,point1Y,point2X,point2Y,asymptoteX})=>`The graph shows a logarithm curve passing through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y} with a vertical asymptote at x equals ${asymptoteX}.`,srLogarithmInteractiveElements:({point1X,point1Y,point2X,point2Y,asymptoteX})=>`Logarithm graph with point 1 at ${point1X} comma ${point1Y}, point 2 at ${point2X} comma ${point2Y}, and vertical asymptote at x equals ${asymptoteX}.`,srLogarithmAsymptote:({asymptoteX})=>`Vertical asymptote at x equals ${asymptoteX}. Use left and right arrow keys to move.`,srAbsoluteValueGraph:"An absolute value function on a coordinate plane.",srAbsoluteValueVertexPoint:({x,y})=>`Vertex point at ${x} comma ${y}.`,srAbsoluteValueSecondPoint:({x,y})=>`Point on arm at ${x} comma ${y}.`,srAbsoluteValueDescription:({x,y,slope})=>`The graph shows an absolute value function with vertex at ${x} comma ${y} and slope ${slope}.`,srAbsoluteValueInteractiveElements:({point1X,point1Y,point2X,point2Y})=>`Absolute value graph with vertex point at ${point1X} comma ${point1Y} and arm point at ${point2X} comma ${point2Y}.`,srTangentGraph:"A tangent function on a coordinate plane.",srTangentInflectionPoint:({x,y})=>`Inflection point at ${x} comma ${y}.`,srTangentSecondPoint:({x,y})=>`Control point at ${x} comma ${y}.`,srTangentDescription:({inflectionX,inflectionY})=>`The graph shows a tangent function with an inflection point at ${inflectionX} comma ${inflectionY}.`,srTangentInteractiveElements:({point1X,point1Y,point2X,point2Y})=>`Tangent graph with inflection point at ${point1X} comma ${point1Y} and control point at ${point2X} comma ${point2Y}.`,imageExploreButton:"Explore image",imageExploreButtonAriaLabel:"Explore image and description",imageAlternativeTitle:"Explore image and description",imageDescriptionLabel:"Description",imageZoomAriaLabel:"Make image bigger.",imageResetZoomAriaLabel:"Close image.",gifPlayButtonLabel:"Play Animation",gifPauseButtonLabel:"Pause Animation"};const errorToString={APPROXIMATED_PI_ERROR:"APPROXIMATED_PI_ERROR",CHOOSE_CORRECT_NUM_ERROR:"chooseCorrectNum",EMPTY_RESPONSE_ERROR:"EMPTY_RESPONSE_ERROR",EXTRA_SYMBOLS_ERROR:"EXTRA_SYMBOLS_ERROR",FILL_ALL_CELLS_ERROR:"fillAllCells",INVALID_CHOICE_SELECTION:"INVALID_CHOICE_SELECTION",INVALID_SELECTION_ERROR:"invalidSelection",MISSING_PERCENT_ERROR:"MISSING_PERCENT_ERROR",MULTIPLICATION_SIGN_ERROR:"MULTIPLICATION_SIGN_ERROR",NEEDS_TO_BE_SIMPLIFIED_ERROR:"NEEDS_TO_BE_SIMPLFIED_ERROR",NOT_NONE_ABOVE_ERROR:"notNoneOfTheAbove",USER_INPUT_EMPTY:"USER_INPUT_EMPTY",USER_INPUT_TOO_LONG:"USER_INPUT_TOO_LONG",WRONG_CASE_ERROR:"WRONG_CASE_ERROR",WRONG_LETTER_ERROR:"WRONG_LETTER_ERROR"};function mapErrorToString(err,translatedStrings){if(!err){return err}return translatedStrings[errorToString[err]]||err}
|
|
1462
|
+
const mockStrings={characterCount:({used,num})=>num===1?`${used} / ${num} Character`:`${used} / ${num} Characters`,closeKeypad:"close math keypad",openKeypad:"open math keypad",mathInputBox:"Math input box",removeHighlight:"Remove highlight",addHighlight:"Add highlight",hintPos:({pos})=>`Hint #${pos}`,errorRendering:({error})=>`Error rendering: ${error}`,APPROXIMATED_PI_ERROR:"Your answer is close, but you may "+"have approximated pi. Enter your "+"answer as a multiple of pi, like "+"<code>12\\ \\text{pi}</code> or "+"<code>2/3\\ \\text{pi}</code>",EMPTY_RESPONSE_ERROR:"There are still more parts of this question to answer.",EXTRA_SYMBOLS_ERROR:"We could not understand your "+"answer. Please check your answer for extra "+"text or symbols.",NEEDS_TO_BE_SIMPLFIED_ERROR:"Your answer is almost correct, "+"but it needs to be simplified.",MISSING_PERCENT_ERROR:"Your answer is almost correct, "+"but it is missing a "+"<code>\\%</code> at the end.",MULTIPLICATION_SIGN_ERROR:"I'm a computer. I only understand "+"multiplication if you use an asterisk "+"(*) as the multiplication sign.",USER_INPUT_EMPTY:"Your answer is empty.",USER_INPUT_TOO_LONG:"Please shorten your response.",WRONG_CASE_ERROR:"Your answer includes use of a variable with the wrong case.",WRONG_LETTER_ERROR:"Your answer includes a wrong variable letter.",invalidSelection:"Make sure you select something for every row.",INVALID_CHOICE_SELECTION:"Invalid choice selection",ERROR_TITLE:"Oops!",ERROR_MESSAGE:"Sorry, I don't understand that!",hints:"Hints",getAnotherHint:"Get another hint",deprecatedStandin:"Sorry, this part of the question is no longer available. 😅 Don't worry, you won't be graded on this part. Keep going!",keepTrying:"Keep trying",tryAgain:"Try again",check:"Check",correctExcited:"Correct!",nextQuestion:"Next question",skipToTitle:({title})=>`Skip to ${title}`,current:"Current",correct:"Correct",correctSelected:"Correct (selected)",incorrect:"Incorrect",incorrectSelected:"Incorrect (selected)",hideExplanation:"Hide explanation",explain:"Explain",INVALID_MESSAGE_PREFIX:"We couldn't grade your answer.",DEFAULT_INVALID_MESSAGE_1:"It looks like you left something blank or ",DEFAULT_INVALID_MESSAGE_2:"entered in an invalid answer.",integerExample:"an integer, like $6$",properExample:"a *proper* fraction, like $1/2$ or $6/10$",simplifiedProperExample:"a *simplified proper* fraction, like $3/5$",improperExample:"an *improper* fraction, like $10/7$ or $14/8$",simplifiedImproperExample:"a *simplified improper* fraction, like $7/4$",mixedExample:"a mixed number, like $1\\ 3/4$",decimalExample:"an *exact* decimal, like $0.75$",percentExample:"a percent, like $12.34\\%$",piExample:"a multiple of pi, like $12\\ \\text{pi}$ or $2/3\\ \\text{pi}$",yourAnswer:"**Your answer should be** ",yourAnswerLabel:"Your answer:",addPoints:"Click to add points",addVertices:"Click to add vertices",tapMultiple:"Tap each dot on the image to select all answers that apply.",tapSingle:"Tap each dot on the image to select an answer.",clickMultiple:"Click each dot on the image to select all answers that apply.",clickSingle:"Click each dot on the image to select an answer.",choices:"Choices:",answers:({num})=>num===1?`${num} answer`:`${num} answers`,hideAnswersToggleLabel:"Hide answer choices",moves:({num})=>num===1?`Moves: ${num}`:`Moves: ${num}`,clickTiles:"Click on the tiles to change the lights.",turnOffLights:"You must turn on all of the lights to continue.",fillAllCells:"Make sure you fill in all cells in the matrix.",molecularDrawing:({content})=>`A molecular structure drawing. SMILES notation: ${content}`,switchDirection:"Switch direction",circleOpen:"Make circle open",circleFilled:"Make circle filled",numDivisions:"Number of divisions:",divisions:({divRangeString})=>`Please make sure the number of divisions is in the range ${divRangeString}.`,dragHandles:"Drag handles to make graph",tapAddPoints:"Tap to add points",false:"False",true:"True",no:"No",yes:"Yes",chooseCorrectNum:"Please choose the correct number of answers.",notNoneOfTheAbove:"'None of the above' may not be selected when other answers are selected.",noneOfTheAbove:"None of the above",chooseNumAnswers:({numCorrect})=>`Choose ${numCorrect} answers:`,chooseAllAnswers:"Choose all answers that apply:",chooseOneAnswer:"Choose 1 answer:",choiceCheckedCorrect:({letter})=>`(Choice ${letter}, Checked, Correct)`,choiceCorrect:({letter})=>`(Choice ${letter}, Correct)`,choiceCheckedIncorrect:({letter})=>`(Choice ${letter}, Checked, Incorrect)`,choiceIncorrect:({letter})=>`(Choice ${letter}, Incorrect)`,choiceChecked:({letter})=>`(Choice ${letter}, Checked)`,choice:({letter})=>`(Choice ${letter})`,notSelected:"not selected",choicesSelected:({num})=>num===1?`${num} choice selected`:`${num} choices selected`,bringBack:"Bring back",openMenuForChoice:({letter})=>`Open menu for Choice ${letter}`,letters:"A B C D E F G H I J K L M N O P Q R S T U V W X Y Z",scrollAnswers:"Scroll Answers",scrollStart:"Scroll to view start of the content",scrollEnd:"Scroll to view the end of the content",rightArrow:"Reaction arrow pointing to the right.",dontUnderstandUnits:"I couldn't understand those units.",checkSigFigs:"Check your significant figures.",answerNumericallyIncorrect:"That answer is numerically incorrect.",checkUnits:"Check your units.",dontUnderstand:"I don't understand that",loading:"Loading...",videoTranscript:"See video transcript",somethingWrong:"Something went wrong.",videoWrapper:"Khan Academy video wrapper",mathInputTitle:"mathematics keyboard",mathInputDescription:"Use keyboard/mouse to interact with math-based input fields",sin:"sin",cos:"cos",tan:"tan",simulationLoadFail:"Sorry, this simulation cannot load.",simulationLocaleWarning:"Sorry, this simulation isn't available in your language.",selectAnAnswer:"Select an answer",srGraphInstructions:"Use the Tab key to move through the interactive elements in the graph. When an interactive element has focus, use Control + Shift + Arrows to move it.",srUnlimitedGraphInstructions:"Press Shift + Enter to interact with the graph. Use the Tab key to move through the interactive elements in the graph and access the graph Action Bar. When an interactive element has focus, use Control + Shift + Arrows to move it or use the Delete key to remove it from the graph. Use the buttons in the Action Bar to add or adjust elements within the graph.",graphKeyboardPrompt:"Press Shift + Enter to interact with the graph",addPoint:"Add Point",removePoint:"Remove Point",closePolygon:"Close shape",openPolygon:"Re-open shape",ungradedInteractiveGraph:"Use this graph to check your thinking, but it does not count as your answer.",srPointAtCoordinates:({num,x,y})=>`Point ${num} at ${x} comma ${y}.`,srInteractiveElements:({elements})=>`Interactive elements: ${elements}`,srNoInteractiveElements:"No interactive elements",srCircleGraph:"A circle on a coordinate plane.",srCircleShape:({centerX,centerY})=>`Circle. The center point is at ${centerX} comma ${centerY}.`,srCircleRadiusPointRight:({radiusPointX,radiusPointY})=>`Right radius endpoint at ${radiusPointX} comma ${radiusPointY}.`,srCircleRadiusPointLeft:({radiusPointX,radiusPointY})=>`Left radius endpoint at ${radiusPointX} comma ${radiusPointY}.`,srCircleRadius:({radius})=>`Circle radius is ${radius}.`,srCircleOuterPoints:({point1X,point1Y,point2X,point2Y,point3X,point3Y,point4X,point4Y})=>`Points on the circle at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, ${point3X} comma ${point3Y}, ${point4X} comma ${point4Y}.`,srLinearGraph:"A line on a coordinate plane.",srLinearGraphPoints:({point1X,point1Y,point2X,point2Y})=>`The line has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`,srLinearGraphSlopeIncreasing:"Its slope increases from left to right.",srLinearGraphSlopeDecreasing:"Its slope decreases from left to right.",srLinearGraphSlopeHorizontal:"Its slope is zero.",srLinearGraphSlopeVertical:"Its slope is undefined.",srLinearGraphXOnlyIntercept:({xIntercept})=>`The line crosses the X-axis at ${xIntercept} comma 0.`,srLinearGraphYOnlyIntercept:({yIntercept})=>`The line crosses the Y-axis at 0 comma ${yIntercept}.`,srLinearGraphBothIntercepts:({xIntercept,yIntercept})=>`The line crosses the X-axis at ${xIntercept} comma 0 and the Y-axis at 0 comma ${yIntercept}.`,srLinearGraphOriginIntercept:"The line crosses the X and Y axes at the graph's origin.",srLinearGrabHandle:({point1X,point1Y,point2X,point2Y})=>`Line going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`,srAngleStartingSide:({x,y})=>`Point 3, starting side at ${x} comma ${y}.`,srAngleEndingSide:({x,y})=>`Point 2, ending side at ${x} comma ${y}.`,srAngleVertexWithAngleMeasure:({x,y,angleMeasure})=>`Point 1, vertex at ${x} comma ${y}. Angle ${angleMeasure} degrees.`,srAngleGraphAriaLabel:"An angle on a coordinate plane.",srAngleGraphAriaDescription:({angleMeasure,vertexX,vertexY,startingSideX,startingSideY,endingSideX,endingSideY})=>`The angle measure is ${angleMeasure} degrees with a vertex at ${vertexX} comma ${vertexY}, a point on the starting side at ${startingSideX} comma ${startingSideY} and a point on the ending side at ${endingSideX} comma ${endingSideY}.`,srAngleInteractiveElements:({vertexX,vertexY,startingSideX,startingSideY,endingSideX,endingSideY})=>`An angle formed by 3 points. The vertex is at ${vertexX} comma ${vertexY}. The starting side point is at ${startingSideX} comma ${startingSideY}. The ending side point is at ${endingSideX} comma ${endingSideY}.`,srSingleSegmentGraphAriaLabel:"A line segment on a coordinate plane.",srMultipleSegmentGraphAriaLabel:({countOfSegments})=>`${countOfSegments} segments on a coordinate plane.`,srMultipleSegmentIndividualLabel:({point1X,point1Y,point2X,point2Y,indexOfSegment})=>`Segment ${indexOfSegment}: Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`,srSingleSegmentLabel:({point1X,point1Y,point2X,point2Y})=>`Endpoint 1 at ${point1X} comma ${point1Y}. Endpoint 2 at ${point2X} comma ${point2Y}.`,srSegmentLength:({length})=>`Segment length ${length} units.`,srSingleSegmentGraphEndpointAriaLabel:({endpointNumber,x,y})=>`Endpoint ${endpointNumber} at ${x} comma ${y}.`,srMultipleSegmentGraphEndpointAriaLabel:({endpointNumber,x,y,indexOfSegment})=>`Endpoint ${endpointNumber} on segment ${indexOfSegment} at ${x} comma ${y}.`,srSegmentGrabHandle:({point1X,point1Y,point2X,point2Y})=>`Segment from ${point1X} comma ${point1Y} to ${point2X} comma ${point2Y}.`,srLinearSystemGraph:"Two lines on a coordinate plane.",srLinearSystemPoints:({lineNumber,point1X,point1Y,point2X,point2Y})=>`Line ${lineNumber} has two points, point 1 at ${point1X} comma ${point1Y} and point 2 at ${point2X} comma ${point2Y}.`,srLinearSystemPoint:({lineNumber,pointSequence,x,y})=>`Point ${pointSequence} on line ${lineNumber} at ${x} comma ${y}.`,srLinearSystemGrabHandle:({lineNumber,point1X,point1Y,point2X,point2Y})=>`Line ${lineNumber} going through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y}.`,srLinearSystemIntersection:({x,y})=>`Line 1 and line 2 intersect at point ${x} comma ${y}.`,srLinearSystemParallel:"Line 1 and line 2 are parallel.",srRayGraph:"A ray on a coordinate plane.",srRayPoints:({point1X,point1Y,point2X,point2Y})=>`The endpoint is at ${point1X} comma ${point1Y} and the ray goes through point ${point2X} comma ${point2Y}.`,srRayGrabHandle:({point1X,point1Y,point2X,point2Y})=>`Ray with endpoint ${point1X} comma ${point1Y} going through point ${point2X} comma ${point2Y}.`,srRayEndpoint:({x,y})=>`Endpoint at ${x} comma ${y}.`,srRayTerminalPoint:({x,y})=>`Through point at ${x} comma ${y}.`,srVectorGraph:"A vector on a coordinate plane.",srVectorPoints:({tailX,tailY,tipX,tipY})=>`The tail is at ${tailX} comma ${tailY} and the tip is at ${tipX} comma ${tipY}.`,srVectorTipPoint:({x,y})=>`Tip point at ${x} comma ${y}.`,srVectorGrabHandle:({tailX,tailY,tipX,tipY})=>`Vector from ${tailX} comma ${tailY} to ${tipX} comma ${tipY}.`,srQuadraticGraph:"A parabola on a 4-quadrant coordinate plane.",srQuadraticFaceUp:"The parabola opens upward.",srQuadraticFaceDown:"The parabola opens downward.",srQuadraticGraphVertexOrigin:"Vertex is at the origin.",srQuadraticGraphVertexXAxis:"Vertex is on the X-axis.",srQuadraticGraphVertexYAxis:"Vertex is on the Y-axis.",srQuadraticGraphVertexQuadrant:({quadrant})=>`Vertex is in quadrant ${quadrant}.`,srQuadraticTwoXIntercepts:({intercept1,intercept2})=>`The X-intercepts are at ${intercept1} comma 0 and ${intercept2} comma 0.`,srQuadraticOneXIntercept:({intercept})=>`The X-intercept is at ${intercept} comma 0.`,srQuadraticYIntercept:({intercept})=>`The Y-intercept is at 0 comma ${intercept}.`,srQuadraticPointOrigin:({pointNumber})=>`Point ${pointNumber} on parabola at the origin.`,srQuadraticPointAxis:({pointNumber,x,y})=>`Point ${pointNumber} on parabola at ${x} comma ${y}.`,srQuadraticPointQuadrant:({pointNumber,x,y,quadrant})=>`Point ${pointNumber} on parabola in quadrant ${quadrant} at ${x} comma ${y}.`,srQuadraticInteractiveElements:({point1X,point1Y,point2X,point2Y,point3X,point3Y})=>`Parabola with points at ${point1X} comma ${point1Y}, ${point2X} comma ${point2Y}, and ${point3X} comma ${point3Y}.`,srPolygonGraph:"A polygon.",srPolygonGraphCoordinatePlane:"A polygon on a coordinate plane.",srPolygonGraphPointsNum:({num})=>`The polygon has ${num} points.`,srPolygonGraphPointsOne:"The polygon has 1 point.",srPolygonElementsNum:({num})=>`A polygon with ${num} points.`,srPolygonElementsOne:"A polygon with 1 point.",srPolygonPointAngleApprox:({angle})=>`Angle approximately equal to ${angle} degrees.`,srPolygonPointAngle:({angle})=>`Angle equal to ${angle} degrees.`,srPolygonSideLength:({pointNum,length})=>`A line segment, length equal to ${length} units, connects to point ${pointNum}.`,srPolygonSideLengthApprox:({pointNum,length})=>`A line segment, length approximately equal to ${length} units, connects to point ${pointNum}.`,srUnlimitedPolygonEmpty:"An empty coordinate plane.",srSinusoidGraph:"A sinusoid function on a coordinate plane.",srSinusoidRootPoint:({x,y})=>`Midline intersection at ${x} comma ${y}.`,srSinusoidMaxPoint:({x,y})=>`Maximum point at ${x} comma ${y}.`,srSinusoidMinPoint:({x,y})=>`Minimum point at ${x} comma ${y}.`,srSinusoidFlatPoint:({x,y})=>`Line through point at ${x} comma ${y}.`,srSinusoidDescription:({minValue,maxValue,cycleStart,cycleEnd})=>`The graph shows a wave with a minimum value of ${minValue} and a maximum value of ${maxValue}. The wave completes a full cycle from ${cycleStart} to ${cycleEnd}.`,srSinusoidInteractiveElements:({point1X,point1Y,point2X,point2Y})=>`Sinusoid graph with midline intersection point at ${point1X} comma ${point1Y} and extremum point at ${point2X} comma ${point2Y}.`,srExponentialGraph:"An exponential curve on a coordinate plane.",srExponentialPoint1:({x,y})=>`Point 1 at ${x} comma ${y}.`,srExponentialPoint2:({x,y})=>`Point 2 at ${x} comma ${y}.`,srExponentialDescription:({point1X,point1Y,point2X,point2Y,asymptoteY})=>`The graph shows an exponential curve passing through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y} with a horizontal asymptote at y equals ${asymptoteY}.`,srExponentialInteractiveElements:({point1X,point1Y,point2X,point2Y,asymptoteY})=>`Exponential graph with point 1 at ${point1X} comma ${point1Y}, point 2 at ${point2X} comma ${point2Y}, and horizontal asymptote at y equals ${asymptoteY}.`,srExponentialAsymptote:({asymptoteY})=>`Horizontal asymptote at y equals ${asymptoteY}. Use up and down arrow keys to move.`,srLogarithmGraph:"A logarithm function on a coordinate plane.",srLogarithmPoint1:({x,y})=>`Point 1 at ${x} comma ${y}.`,srLogarithmPoint2:({x,y})=>`Point 2 at ${x} comma ${y}.`,srLogarithmDescription:({point1X,point1Y,point2X,point2Y,asymptoteX})=>`The graph shows a logarithm curve passing through point ${point1X} comma ${point1Y} and point ${point2X} comma ${point2Y} with a vertical asymptote at x equals ${asymptoteX}.`,srLogarithmInteractiveElements:({point1X,point1Y,point2X,point2Y,asymptoteX})=>`Logarithm graph with point 1 at ${point1X} comma ${point1Y}, point 2 at ${point2X} comma ${point2Y}, and vertical asymptote at x equals ${asymptoteX}.`,srLogarithmAsymptote:({asymptoteX})=>`Vertical asymptote at x equals ${asymptoteX}. Use left and right arrow keys to move.`,srAbsoluteValueGraph:"An absolute value function on a coordinate plane.",srAbsoluteValueVertexPoint:({x,y})=>`Vertex point at ${x} comma ${y}.`,srAbsoluteValueSecondPoint:({x,y})=>`Point on arm at ${x} comma ${y}.`,srAbsoluteValueDescription:({x,y,slope})=>`The graph shows an absolute value function with vertex at ${x} comma ${y} and slope ${slope}.`,srAbsoluteValueInteractiveElements:({point1X,point1Y,point2X,point2Y})=>`Absolute value graph with vertex point at ${point1X} comma ${point1Y} and arm point at ${point2X} comma ${point2Y}.`,srTangentGraph:"A tangent function on a coordinate plane.",srTangentInflectionPoint:({x,y})=>`Inflection point at ${x} comma ${y}.`,srTangentSecondPoint:({x,y})=>`Control point at ${x} comma ${y}.`,srTangentDescription:({inflectionX,inflectionY})=>`The graph shows a tangent function with an inflection point at ${inflectionX} comma ${inflectionY}.`,srTangentInteractiveElements:({point1X,point1Y,point2X,point2Y})=>`Tangent graph with inflection point at ${point1X} comma ${point1Y} and control point at ${point2X} comma ${point2Y}.`,imageExploreButton:"Explore image",imageExploreButtonAriaLabel:"Explore image and description",imageAlternativeTitle:"Explore image and description",imageDescriptionLabel:"Description",imageZoomAriaLabel:"Make image bigger.",imageResetZoomAriaLabel:"Close image.",gifPlayButtonLabel:"Play Animation",gifPauseButtonLabel:"Pause Animation"};const errorToString={APPROXIMATED_PI_ERROR:"APPROXIMATED_PI_ERROR",CHOOSE_CORRECT_NUM_ERROR:"chooseCorrectNum",EMPTY_RESPONSE_ERROR:"EMPTY_RESPONSE_ERROR",EXTRA_SYMBOLS_ERROR:"EXTRA_SYMBOLS_ERROR",FILL_ALL_CELLS_ERROR:"fillAllCells",INVALID_CHOICE_SELECTION:"INVALID_CHOICE_SELECTION",INVALID_SELECTION_ERROR:"invalidSelection",MISSING_PERCENT_ERROR:"MISSING_PERCENT_ERROR",MULTIPLICATION_SIGN_ERROR:"MULTIPLICATION_SIGN_ERROR",NEEDS_TO_BE_SIMPLIFIED_ERROR:"NEEDS_TO_BE_SIMPLFIED_ERROR",NOT_NONE_ABOVE_ERROR:"notNoneOfTheAbove",USER_INPUT_EMPTY:"USER_INPUT_EMPTY",USER_INPUT_TOO_LONG:"USER_INPUT_TOO_LONG",WRONG_CASE_ERROR:"WRONG_CASE_ERROR",WRONG_LETTER_ERROR:"WRONG_LETTER_ERROR"};function mapErrorToString(err,translatedStrings){if(!err){return err}return translatedStrings[errorToString[err]]||err}
|
|
1463
1463
|
|
|
1464
1464
|
const mockPerseusI18nContext={strings:mockStrings,locale:"en"};const PerseusI18nContext=React__namespace.createContext(process.env.NODE_ENV==="test"||process.env.STORYBOOK?mockPerseusI18nContext:null);function PerseusI18nContextProvider({children,strings,locale}){return jsxRuntimeExports.jsx(PerseusI18nContext.Provider,{value:{strings,locale},children:children})}const usePerseusI18n=()=>React.useContext(PerseusI18nContext);
|
|
1465
1465
|
|
|
@@ -1701,7 +1701,7 @@ const{interactiveSizes}=constants;const smMax=articleMaxWidthTableInPx;const mdM
|
|
|
1701
1701
|
|
|
1702
1702
|
function getWidgetTypeByWidgetId(widgetId,widgetMap){const widget=widgetMap[widgetId];return widget?.type??null}function getWidgetSubType(widgetType,widgetOptions){switch(widgetType){case "interactive-graph":const graphOptions=widgetOptions;return graphOptions.graph?.type??null;case "radio":const radioOptions=widgetOptions;return radioOptions.multipleSelect?"multiple-select":"single-select";default:return null}}function getWidgetSubTypeByWidgetId(widgetId,widgetMap){const widget=widgetMap[widgetId];if(!widget){return null}return getWidgetSubType(widget.type,widget.options)}function contentHasWidgetType(type,content,widgetMap){return perseusCore.getWidgetIdsFromContentByType(type,content,widgetMap).length>0}function getWidgetFromWidgetMap(widgetId,widgetMap){return widgetMap[widgetId]??null}function getWidgetsFromWidgetMap(widgetIds,widgetMap){const widgets={};widgetIds.forEach(widgetId=>{const widget=getWidgetFromWidgetMap(widgetId,widgetMap);if(widget){widgets[widgetId]=widget;}});return widgets}
|
|
1703
1703
|
|
|
1704
|
-
const DEFAULT_TRACKING="";const DEFAULT_LINTABLE=false;const widgets=new perseusCore.Registry("Perseus widget registry");const editors=new perseusCore.Registry("Perseus widget editor registry");const registerWidget=(type,widget)=>{widgets.set(type,widget);};const registerWidgets=widgetArr=>{widgetArr.forEach(widget=>{registerWidget(widget.name,widget);});};const replaceWidget=(type,replacementType)=>{const substituteWidget=widgets.get(replacementType);if(!substituteWidget){const errorMsg=`Failed to replace ${type} with ${replacementType}`;throw new perseusCore.PerseusError(errorMsg,perseusCore.Errors.Internal)}registerWidget(type,substituteWidget);};const replaceDeprecatedWidgets=()=>{replaceWidget("transformer","deprecated-standin");replaceWidget("lights-puzzle","deprecated-standin");replaceWidget("reaction-diagram","deprecated-standin");replaceWidget("sequence","deprecated-standin");replaceWidget("simulator","deprecated-standin");replaceWidget("unit-input","deprecated-standin");replaceWidget("passage","deprecated-standin");replaceWidget("passage-ref","deprecated-standin");replaceWidget("passage-ref-target","deprecated-standin");};const registerEditors=editorsToRegister=>{editorsToRegister.forEach(editor=>{if(!editor.widgetName){throw new perseusCore.PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`,perseusCore.Errors.Internal)}editors.set(editor.widgetName,editor);});};const replaceEditor=(type,replacementType)=>{const substituteEditor=editors.get(replacementType);if(!substituteEditor&&Log){const errorMsg=`Failed to replace editor ${type} with ${replacementType}`;Log.error(errorMsg,perseusCore.Errors.Internal);return}editors.set(type,substituteEditor);};const replaceDeprecatedEditors=()=>{replaceEditor("transformer","deprecated-standin");replaceEditor("lights-puzzle","deprecated-standin");replaceEditor("reaction-diagram","deprecated-standin");replaceEditor("sequence","deprecated-standin");replaceEditor("simulator","deprecated-standin");replaceEditor("unit-input","deprecated-standin");replaceEditor("passage","deprecated-standin");replaceEditor("passage-ref","deprecated-standin");replaceEditor("passage-ref-target","deprecated-standin");};const getWidget=type=>{const widget=widgets.get(type);if(widget==null){return null}if(widget.getWidget){return widget.getWidget()}return widget.widget};const getWidgetExport=type=>{return widgets.get(type)??null};const getEditor=type=>{return editors.get(type)??null};const getVersion=type=>{const widget=widgets.get(type);if(widget!=null){return widget.version||{major:0,minor:0}}return};const getVersionVector=()=>{const version={};widgets.keys().forEach(type=>{version[type]=getVersion(type);});return version};const getPublicWidgets=()=>{return widgets.entries().reduce((acc,[key,value])=>{if(process.env.STORYBOOK||!value.hidden){acc[key]=value;}return acc},{})};const getAllWidgetTypes=()=>{return widgets.keys()};const supportsStaticMode=type=>{const widgetInfo=widgets.get(type);return widgetInfo&&widgetInfo.getCorrectUserInput!=null};const getTracking=type=>{const widgetExport=widgets.get(type);return widgetExport&&widgetExport.tracking||DEFAULT_TRACKING};const isLintable=type=>{const widgetExports=widgets.get(type);return widgetExports&&widgetExports.isLintable||DEFAULT_LINTABLE};
|
|
1704
|
+
const DEFAULT_TRACKING="";const DEFAULT_LINTABLE=false;const widgets=new perseusCore.Registry("Perseus widget registry");const editors=new perseusCore.Registry("Perseus widget editor registry");const registerWidget=(type,widget)=>{widgets.set(type,widget);};const registerWidgets=widgetArr=>{widgetArr.forEach(widget=>{registerWidget(widget.name,widget);});};const replaceWidget=(type,replacementType)=>{const substituteWidget=widgets.get(replacementType);if(!substituteWidget){const errorMsg=`Failed to replace ${type} with ${replacementType}`;throw new perseusCore.PerseusError(errorMsg,perseusCore.Errors.Internal)}registerWidget(type,substituteWidget);};const replaceDeprecatedWidgets=()=>{replaceWidget("transformer","deprecated-standin");replaceWidget("lights-puzzle","deprecated-standin");replaceWidget("reaction-diagram","deprecated-standin");replaceWidget("sequence","deprecated-standin");replaceWidget("simulator","deprecated-standin");replaceWidget("unit-input","deprecated-standin");replaceWidget("passage","deprecated-standin");replaceWidget("passage-ref","deprecated-standin");replaceWidget("passage-ref-target","deprecated-standin");};const registerEditors=editorsToRegister=>{editorsToRegister.forEach(editor=>{if(!editor.widgetName){throw new perseusCore.PerseusError(`Editor ${editor.displayName} doesn't have a widgetName property`,perseusCore.Errors.Internal)}editors.set(editor.widgetName,editor);});};const replaceEditor=(type,replacementType)=>{const substituteEditor=editors.get(replacementType);if(!substituteEditor&&Log){const errorMsg=`Failed to replace editor ${type} with ${replacementType}`;Log.error(errorMsg,perseusCore.Errors.Internal);return}editors.set(type,substituteEditor);};const replaceDeprecatedEditors=()=>{replaceEditor("transformer","deprecated-standin");replaceEditor("lights-puzzle","deprecated-standin");replaceEditor("reaction-diagram","deprecated-standin");replaceEditor("sequence","deprecated-standin");replaceEditor("simulator","deprecated-standin");replaceEditor("unit-input","deprecated-standin");replaceEditor("passage","deprecated-standin");replaceEditor("passage-ref","deprecated-standin");replaceEditor("passage-ref-target","deprecated-standin");};const getWidget=type=>{const widget=widgets.get(type);if(widget==null){return null}if(widget.getWidget){return widget.getWidget()}return widget.widget};const getWidgetExport=type=>{return widgets.get(type)??null};const getEditor=type=>{return editors.get(type)??null};const getVersion=type=>{const widget=widgets.get(type);if(widget!=null){return widget.version||{major:0,minor:0}}return};const getVersionVector=()=>{const version={};widgets.keys().forEach(type=>{version[type]=getVersion(type);});return version};const getPublicWidgets=()=>{return widgets.entries().reduce((acc,[key,value])=>{if(process.env.STORYBOOK||!value.hidden){acc[key]=value;}return acc},{})};const getAllWidgetTypes=()=>{return widgets.keys()};const supportsStaticMode=type=>{const widgetInfo=widgets.get(type);return widgetInfo&&widgetInfo.getCorrectUserInput!=null};const supportsUngraded=type=>{const widgetInfo=widgets.get(type);return widgetInfo?.supportsUngraded===true};const getTracking=type=>{const widgetExport=widgets.get(type);return widgetExport&&widgetExport.tracking||DEFAULT_TRACKING};const isLintable=type=>{const widgetExports=widgets.get(type);return widgetExports&&widgetExports.isLintable||DEFAULT_LINTABLE};
|
|
1705
1705
|
|
|
1706
1706
|
var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
1707
1707
|
__proto__: null,
|
|
@@ -1721,12 +1721,13 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
1721
1721
|
replaceDeprecatedWidgets: replaceDeprecatedWidgets,
|
|
1722
1722
|
replaceEditor: replaceEditor,
|
|
1723
1723
|
replaceWidget: replaceWidget,
|
|
1724
|
-
supportsStaticMode: supportsStaticMode
|
|
1724
|
+
supportsStaticMode: supportsStaticMode,
|
|
1725
|
+
supportsUngraded: supportsUngraded
|
|
1725
1726
|
});
|
|
1726
1727
|
|
|
1727
1728
|
class WidgetContainer extends React__namespace.Component{componentDidMount(){if(this.props.widgetProps.apiOptions.isMobile){const containerWidth=ReactDOM__namespace.default.findDOMNode(this).offsetWidth;this.setState({sizeClass:getClassFromWidth(containerWidth)});}}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.type!==nextProps.type){throw new Error("WidgetContainer can't change widget type; set a different "+"key instead to recreate the container.")}}render(){let className=classNames__default.default({"perseus-widget-container":true,"widget-highlight":this.props.shouldHighlight,"widget-nohighlight":!this.props.shouldHighlight,"perseus-widget__definition":this.props.type==="definition"});const type=this.props.type;const userAgent=navigator.userAgent;const WidgetType=getWidget(type);if(WidgetType==null){console.warn(`Widget type '${type}' not found!`);return jsxRuntimeExports.jsx("div",{className:className})}const subType=getWidgetSubType(type,this.props.widgetProps)??"null";let alignment=this.props.widgetProps.alignment;if(alignment==="default"){alignment=perseusCore.CoreWidgetRegistry.getDefaultAlignment(type);}className+=perseusCore.CoreWidgetRegistry.getAlignmentClassName(type,alignment);const apiOptions=this.props.widgetProps.apiOptions;const isStatic=this.props.widgetProps.static||apiOptions.readOnly;const staticContainerStyles={position:"relative",overflow:"visible"};const staticOverlayStyles={width:"100%",height:"100%",position:"absolute",top:0,left:0,zIndex:3};const linterContext=isLintable(type)?this.props.linterContext:{...this.props.linterContext,highlightLint:false};return jsxRuntimeExports.jsx("div",{className:className,style:isStatic?staticContainerStyles:{},children:jsxRuntimeExports.jsx(DependenciesContext.Consumer,{children:({analytics})=>jsxRuntimeExports.jsxs(ErrorBoundary,{metadata:{widget_type:type,widget_id:this.props.id},onError:error=>{analytics.onAnalyticsEvent({type:"perseus:widget-rendering-error:ti",payload:{widgetSubType:subType,widgetType:type,widgetId:this.props.id,message:error.message,stack:error.stack??"No stack trace available",userAgent:userAgent}});},children:[jsxRuntimeExports.jsx(WidgetType,{...this.props.widgetProps,linterContext:linterContext,containerSizeClass:this.state.sizeClass,ref:this.widgetRef}),isStatic&&jsxRuntimeExports.jsx("div",{style:staticOverlayStyles})]})})})}constructor(...args){super(...args),this.widgetRef=React__namespace.createRef(),this.state={sizeClass:containerSizeClass.MEDIUM},this.getWidget=()=>{return this.widgetRef.current};}}WidgetContainer.defaultProps={linterContext:PerseusLinter.linterContextDefault};
|
|
1728
1729
|
|
|
1729
|
-
const rContainsNonWhitespace=/\S/;const rImageURL=/(web\+graphie|https):\/\/[^\s]*/;const noopOnRender=()=>{};const makeContainerId=id=>"container:"+id;const isIdPathPrefix=function(prefixArray,wholeArray){if(prefixArray===null||wholeArray===null){return prefixArray===wholeArray}return ___default.default.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return ___default.default.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return perseusCore.splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:perseusCore.getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!___default.default.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.handleRender({});this._currentFocus=null;this.props.initializeUserInput?.(this.props.widgets,this.props.problemNum??0);if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}UNSAFE_componentWillReceiveProps(nextProps){if(isDifferentQuestion(this.props,nextProps)){this.props.initializeUserInput?.(nextProps.widgets,nextProps.problemNum??0);this.setState(this._getInitialWidgetState(nextProps));}}shouldComponentUpdate(nextProps,nextState){if(this.props.alwaysUpdate){return true}const stateChanged=!___default.default.isEqual(this.state,nextState);const propsChanged=!___default.default.isEqual(this.props,nextProps);return propsChanged||stateChanged}componentDidUpdate(prevProps,prevState){this.handleRender(prevProps);if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}if(this.props.userInput&&!___default.default.isEqual(this.props.userInput,prevProps.userInput)){this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}}componentWillUnmount(){this.widgetIds=[];if(this.translationIndex!=null){getDependencies().rendererTranslationComponents.removeComponentAtIndex(this.translationIndex);}this._isMounted=false;}_isAnswerable(){if(this.props.userInput){return this.emptyWidgets().length===0}return false}_getWidgetIndexById(id){const widgetIndex=this.widgetIds.indexOf(id);if(widgetIndex<0){Log.error("Unable to get widget index in _getWidgetIndexById",perseusCore.Errors.Internal,{loggedMetadata:{widgets:JSON.stringify(this.props.widgets),widgetId:JSON.stringify(id)}});return 0}return widgetIndex}getWidgetProps(widgetId){const apiOptions=this.getApiOptions();const widgetProps=this.props.widgets[widgetId].options;const widgetInfo=this.state.widgetInfo[widgetId];if(!this._interactionTrackers){this._interactionTrackers={};}let interactionTracker=this._interactionTrackers[widgetId];if(!interactionTracker){interactionTracker=this._interactionTrackers[widgetId]=new InteractionTracker(apiOptions.trackInteraction,widgetInfo&&widgetInfo.type,widgetId,getTracking(widgetInfo&&widgetInfo.type));}return {...widgetProps,userInput:this.props.userInput?.[widgetId],widgetId:widgetId,widgetIndex:this._getWidgetIndexById(widgetId),alignment:widgetInfo&&widgetInfo.alignment,static:widgetInfo?.static,problemNum:this.props.problemNum,apiOptions:this.getApiOptions(),keypadElement:this.props.keypadElement,showSolutions:this.props.showSolutions,onFocus:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewMode:this.props.reviewMode,handleUserInput:newUserInput=>{const updatedUserInput={...this.props.userInput,[widgetId]:newUserInput};const emptyWidgetIds=perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,updatedUserInput,this.context.locale);const widgetsEmpty=emptyWidgetIds.length>0;this.props.handleUserInput?.(widgetId,newUserInput,widgetsEmpty);this.props.apiOptions?.interactionCallback?.(updatedUserInput);},trackInteraction:interactionTracker.track}}getSerializedState(){return perseusCore.mapObject(this.props.widgets,(widgetData,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return widgetData.options})}emptyWidgets(){if(!this.props.userInput){throw new Error(`emptyWidgets called without providing userInput to Renderer`)}return perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale)}getUserInputMap(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInputMap called without providing userInput to Renderer`)}return userInput}getPromptJSON(){const{content}=this.props;const widgetJSON={};this.widgetIds.forEach(id=>{const widget=this.getWidgetInstance(id);widgetJSON[id]=widget?.getPromptJSON?.()||{};});return {content,widgets:widgetJSON}}score(){if(!this.props.userInput){throw new Error(`score called without providing userInput to Renderer`)}const scores=perseusScore.scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=perseusScore.flattenScores(scores);return combinedScore}render(){const apiOptions=this.getApiOptions();const content=this.getContent(this.props,this.state);this.widgetIds=[];if(this.shouldRenderJiptPlaceholder(this.props,this.state)){if(!this.translationIndex){this.translationIndex=getDependencies().rendererTranslationComponents.addComponent(this);}if(!apiOptions.isArticle){return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{"data-perseus-component-index":this.translationIndex,children:content})})}}this._isTwoColumn=false;const parsedMarkdown=this.props.inline?PerseusMarkdown.parseInline(content,{isJipt:this.translationIndex!=null}):PerseusMarkdown.parse(content,{isJipt:this.translationIndex!=null});if(this.props.linterContext.highlightLint){const fullLinterContext={content:this.props.content,widgets:this.props.widgets,...this.props.linterContext};PerseusLinter__namespace.runLinter(parsedMarkdown,fullLinterContext,true);this._translationLinter.applyLintErrors(parsedMarkdown,[...this.state.translationLintErrors,...this.props.legacyPerseusLint||[]]);}const markdownContents=this.outputMarkdown(parsedMarkdown,{baseElements:apiOptions.baseElements});const className=classNames__default.default({[ClassNames.RENDERER]:true,[ClassNames.RESPONSIVE_RENDERER]:true,[ClassNames.TWO_COLUMN_RENDERER]:this._isTwoColumn});return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{className:className,children:markdownContents})})}constructor(props){super(props),this._widgetContainers=new Map,this.getApiOptions=()=>{return {...ApiOptions.defaults,...this.props.apiOptions}},this._getInitialWidgetState=props=>{const allWidgetInfo=perseusCore.applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo}},this._getDefaultWidgetInfo=widgetId=>{const widgetIdParts=Util.rTypeFromWidgetId.exec(widgetId);if(widgetIdParts==null){return {}}return {type:widgetIdParts[1],graded:true,options:{}}},this._getWidgetInfo=widgetId=>{return this.state.widgetInfo[widgetId]||this._getDefaultWidgetInfo(widgetId)},this.renderWidget=(impliedType,id,state)=>{const widgetInfo=this.state.widgetInfo[id];if(widgetInfo&&widgetInfo.alignment==="full-width"){state.foundFullWidth=true;}if(widgetInfo){const type=widgetInfo&&widgetInfo.type||impliedType;let shouldHighlight=false;if(this.props.highlightEmptyWidgets&&this.props.userInput){shouldHighlight=this.emptyWidgets().includes(id);}return jsxRuntimeExports.jsx(WidgetContainer,{id:id,ref:node=>{const containerId=makeContainerId(id);if(node!=null){this._widgetContainers.set(containerId,node);}else {this._widgetContainers.delete(containerId);}},type:type,widgetProps:this.getWidgetProps(id),shouldHighlight:shouldHighlight,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.findInternalWidgets=filterCriterion=>{let filterFunc;if(typeof filterCriterion==="string"){if(filterCriterion.indexOf(" ")!==-1){const widgetId=filterCriterion;filterFunc=(id,widgetInfo,widget)=>id===widgetId;}else {const widgetType=filterCriterion;filterFunc=(id,widgetInfo,widget)=>{return widgetInfo.type===widgetType};}}else {filterFunc=filterCriterion;}const results=this.widgetIds.filter(id=>{const widgetInfo=this._getWidgetInfo(id);const widget=this.getWidgetInstance(id);return filterFunc(id,widgetInfo,widget)}).map(this.getWidgetInstance);return results},this.findWidgets=filterCriterion=>{return [...this.findInternalWidgets(filterCriterion),...this.props.findExternalWidgets(filterCriterion)]},this.getWidgetInstance=id=>{const ref=this._widgetContainers.get(makeContainerId(id));if(!ref){return null}return ref.getWidget()},this._onWidgetFocus=(id,focusPath=[])=>{if(!___default.default.isArray(focusPath)){throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),perseusCore.Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!___default.default.isEqual(fullPath,blurringFocusPath)){return}___default.default.defer(()=>{if(___default.default.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.getContent=(props,state)=>{return state.jiptContent||props.content},this.shouldRenderJiptPlaceholder=(props,state)=>{return getDependencies().JIPT.useJIPT&&state.jiptContent==null&&props.content.indexOf("crwdns")!==-1},this.replaceJiptContent=(content,paragraphIndex)=>{if(paragraphIndex==null){this.setState({jiptContent:content});}else {const codeFenceRegex=/^\s*(`{3,}|~{3,})\s*(\S+)?\s*\n([\s\S]+?)\s*\1\s*$/;if(codeFenceRegex.test(content));else if(/\S\n\s*\n\S/.test(content)){content="$\\large{\\red{\\text{Please translate each "+"paragraph to a single paragraph.}}}$";}else if(/^\s*$/.test(content)){content="$\\large{\\red{\\text{Translated paragraph is "+"currently empty}}}$";}const allContent=this.getContent(this.props,this.state);const paragraphs=JiptParagraphs.parseToArray(allContent);paragraphs[paragraphIndex]=content;this.setState({jiptContent:JiptParagraphs.joinFromArray(paragraphs)});}},this.outputMarkdown=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;state.paragraphIndex=i;const nodeOut=this.outputMarkdown(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}this._foundTextNodes=false;state.foundFullWidth=false;const output=this.outputNested(ast,state);let className;if(this.translationIndex!=null){className=null;}else {className=classNames__default.default({"perseus-paragraph-centered":!this._foundTextNodes,"perseus-paragraph-full-width":state.foundFullWidth&&ast.content.length===1});}return jsxRuntimeExports.jsx(QuestionParagraph,{className:className,translationIndex:this.translationIndex,paragraphIndex:state.paragraphIndex,inline:this.props.inline,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:output})},state.key)},this.outputNested=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;const nodeOut=this.outputNested(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}return this.outputNode(ast,this.outputNested,state)},this.outputNode=(node,nestedOutput,state)=>{const apiOptions=this.getApiOptions();const imagePlaceholder=apiOptions.imagePlaceholder;if(node.type==="widget"){const widgetPlaceholder=apiOptions.widgetPlaceholder;if(widgetPlaceholder){return widgetPlaceholder}this._foundTextNodes=true;if(this.widgetIds.includes(node.id)){return jsxRuntimeExports.jsx("span",{className:"renderer-widget-error",children:["Widget [[","☃"," ",node.id,"]] already exists."].join("")},state.key)}this.widgetIds.push(node.id);return this.renderWidget(node.widgetType,node.id,state)}if(node.type==="blockMath"){const content=preprocessTex(node.content);const innerStyle={overflowX:"auto",overflowY:"hidden",paddingTop:10,paddingBottom:10,marginTop:-10,marginBottom:-10};if(apiOptions.isMobile){const margin=16;const outerStyle={marginLeft:-16,marginRight:-16};const horizontalPadding={paddingLeft:margin,paddingRight:margin};const mobileInnerStyle={...innerStyle,...styles$z.mobileZoomableParentFix};return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",style:outerStyle,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:{...mobileInnerStyle,...horizontalPadding},children:jsxRuntimeExports.jsx(ZoomableTeX,{children:content})})})},state.key)}return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:innerStyle,children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{setAssetStatus:setAssetStatus,children:content})})})})},state.key)}if(node.type==="math"){const tex=node.content;return jsxRuntimeExports.jsx("span",{style:{whiteSpace:"nowrap"},children:jsxRuntimeExports.jsxs(ErrorBoundary,{children:[jsxRuntimeExports.jsx("span",{}),jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{onRender:this.props.onRender,setAssetStatus:setAssetStatus,children:tex})}),jsxRuntimeExports.jsx("span",{})]})},state.key)}if(node.type==="image"){if(imagePlaceholder){return imagePlaceholder}const extraAttrs=___default.default.has(this.props.images,node.target)?this.props.images[node.target]:null;const responsive=!state.inTable;return jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{allowZoom:true,setAssetStatus:setAssetStatus,src:PerseusMarkdown.sanitizeUrl(node.target),alt:node.alt,title:node.title,responsive:responsive,onUpdate:this.props.onRender,zoomToFullSizeOnMobile:apiOptions.isMobile&&apiOptions.isArticle,...extraAttrs})})},state.key)}if(node.type==="columns"){this._isTwoColumn=true;return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)}if(node.type==="text"){if(rContainsNonWhitespace.test(node.content)){this._foundTextNodes=true;}if(imagePlaceholder&&rImageURL.test(node.content)){return imagePlaceholder}return node.content}if(node.type==="table"||node.type==="titledTable"){const output=PerseusMarkdown.ruleOutput(node,nestedOutput,{...state,isMobile:apiOptions.isMobile,inTable:true});if(!apiOptions.isMobile){return output}const outerStyle={marginLeft:-16,marginRight:-16};const innerStyle={paddingLeft:0,paddingRight:0};const mobileInnerStyle={...innerStyle,...styles$z.mobileZoomableParentFix};const wrappedOutput=jsxRuntimeExports.jsx("div",{style:{...mobileInnerStyle,overflowX:"auto"},children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(Zoomable,{animateHeight:true,children:output})})});return jsxRuntimeExports.jsx("div",{style:outerStyle,children:wrappedOutput})}return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)},this.handleRender=prevProps=>{const onRender=this.props.onRender;const oldOnRender=prevProps.onRender;if(onRender!==noopOnRender||oldOnRender!==noopOnRender){const $images=$__default.default(ReactDOM__namespace.default.findDOMNode(this)).find("img");if(oldOnRender!==noopOnRender){$images.off("load",oldOnRender);}if(onRender!==noopOnRender){$images.on("load",onRender);}}onRender();},this._setCurrentFocus=path=>{const apiOptions=this.getApiOptions();if(!isIdPathPrefix(path,this._currentFocus)){const prevFocus=this._currentFocus;if(prevFocus){this.blurPath(prevFocus);}this._currentFocus=path;apiOptions.onFocusChange(this._currentFocus,prevFocus);}},this.focus=()=>{let id;let focusResult;for(let i=0;i<this.widgetIds.length;i++){const widgetId=this.widgetIds[i];const widget=this.getWidgetInstance(widgetId);const widgetFocusResult=widget?.focus?.();if(widgetFocusResult){id=widgetId;focusResult=widgetFocusResult;break}}if(id){let path;if(typeof focusResult==="object"){path=[id].concat(focusResult.path||[]);Log.error("Renderer received a focus result of type 'object' "+"instead of the expected type 'boolean'",perseusCore.Errors.Internal,{loggedMetadata:{focusResult:JSON.stringify(focusResult)}});}else {path=[id];}this._setCurrentFocus(path);return true}},this.getDOMNodeForPath=path=>{const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){const container=this._widgetContainers.get(makeContainerId(widgetId));if(container){return ReactDOM__namespace.default.findDOMNode(container)}return ReactDOM__namespace.default.findDOMNode(widget)}},this.getInputPaths=()=>{const inputPaths=[];this.widgetIds.forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getInputPaths){const widgetInputPaths=widget.getInputPaths();widgetInputPaths.forEach(inputPath=>{const relativeInputPath=[widgetId].concat(inputPath);inputPaths.push(relativeInputPath);});}});return inputPaths},this.focusPath=path=>{if(___default.default.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!___default.default.isEqual(this._currentFocus,path)){return}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget){const blurWidget=this.getWidgetInstance(widgetId);blurWidget?.blurInputPath?.(interWidgetPath);}},this.blur=()=>{if(this._currentFocus){this.blurPath(this._currentFocus);}},this.serialize=()=>{const state={};___default.default.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!___default.default.isEmpty(s)){state[id]=s;}},this);return state},this.getWidgetIds=()=>{return this.widgetIds},this.handletranslationLintErrors=lintErrors=>{if(!this._isMounted){return}this.setState({translationLintErrors:lintErrors});};this._translationLinter=new TranslationLinter;this.state={jiptContent:null,translationLintErrors:[],...this._getInitialWidgetState(props)};}}Renderer.contextType=PerseusI18nContext;Renderer.defaultProps={content:"",widgets:{},images:{},showSolutions:"none",onRender:noopOnRender,findExternalWidgets:()=>[],alwaysUpdate:false,reviewMode:false,linterContext:PerseusLinter__namespace.linterContextDefault};const styles$z={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
|
|
1730
|
+
const rContainsNonWhitespace=/\S/;const rImageURL=/(web\+graphie|https):\/\/[^\s]*/;const noopOnRender=()=>{};const makeContainerId=id=>"container:"+id;const isIdPathPrefix=function(prefixArray,wholeArray){if(prefixArray===null||wholeArray===null){return prefixArray===wholeArray}return ___default.default.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return ___default.default.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return perseusCore.splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:perseusCore.getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!___default.default.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.handleRender({});this._currentFocus=null;this.props.initializeUserInput?.(this.props.widgets,this.props.problemNum??0);if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}UNSAFE_componentWillReceiveProps(nextProps){if(isDifferentQuestion(this.props,nextProps)){this.props.initializeUserInput?.(nextProps.widgets,nextProps.problemNum??0);this.setState(this._getInitialWidgetState(nextProps));}}shouldComponentUpdate(nextProps,nextState){if(this.props.alwaysUpdate){return true}const stateChanged=!___default.default.isEqual(this.state,nextState);const propsChanged=!___default.default.isEqual(this.props,nextProps);return propsChanged||stateChanged}componentDidUpdate(prevProps,prevState){this.handleRender(prevProps);if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}if(this.props.userInput&&!___default.default.isEqual(this.props.userInput,prevProps.userInput)){this.props.apiOptions?.answerableCallback?.(this._isAnswerable());}}componentWillUnmount(){this.widgetIds=[];if(this.translationIndex!=null){getDependencies().rendererTranslationComponents.removeComponentAtIndex(this.translationIndex);}this._isMounted=false;}_isAnswerable(){if(this.props.userInput){return this.emptyWidgets().length===0}return false}_getWidgetIndexById(id){const widgetIndex=this.widgetIds.indexOf(id);if(widgetIndex<0){Log.error("Unable to get widget index in _getWidgetIndexById",perseusCore.Errors.Internal,{loggedMetadata:{widgets:JSON.stringify(this.props.widgets),widgetId:JSON.stringify(id)}});return 0}return widgetIndex}getWidgetProps(widgetId){const apiOptions=this.getApiOptions();const widgetProps=this.props.widgets[widgetId].options;const widgetInfo=this.state.widgetInfo[widgetId];if(!this._interactionTrackers){this._interactionTrackers={};}let interactionTracker=this._interactionTrackers[widgetId];if(!interactionTracker){interactionTracker=this._interactionTrackers[widgetId]=new InteractionTracker(apiOptions.trackInteraction,widgetInfo&&widgetInfo.type,widgetId,getTracking(widgetInfo&&widgetInfo.type));}return {...widgetProps,userInput:this.props.userInput?.[widgetId],widgetId:widgetId,widgetIndex:this._getWidgetIndexById(widgetId),alignment:widgetInfo&&widgetInfo.alignment,static:widgetInfo?.static,graded:widgetInfo?.graded,problemNum:this.props.problemNum,apiOptions:this.getApiOptions(),keypadElement:this.props.keypadElement,showSolutions:this.props.showSolutions,onFocus:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewMode:this.props.reviewMode,handleUserInput:newUserInput=>{const updatedUserInput={...this.props.userInput,[widgetId]:newUserInput};const emptyWidgetIds=perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,updatedUserInput,this.context.locale);const widgetsEmpty=emptyWidgetIds.length>0;this.props.handleUserInput?.(widgetId,newUserInput,widgetsEmpty);this.props.apiOptions?.interactionCallback?.(updatedUserInput);},trackInteraction:interactionTracker.track}}getSerializedState(){return perseusCore.mapObject(this.props.widgets,(widgetData,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return widgetData.options})}emptyWidgets(){if(!this.props.userInput){throw new Error(`emptyWidgets called without providing userInput to Renderer`)}return perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale)}getUserInputMap(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInputMap called without providing userInput to Renderer`)}return userInput}getPromptJSON(){const{content}=this.props;const widgetJSON={};this.widgetIds.forEach(id=>{const widget=this.getWidgetInstance(id);widgetJSON[id]=widget?.getPromptJSON?.()||{};});return {content,widgets:widgetJSON}}score(){if(!this.props.userInput){throw new Error(`score called without providing userInput to Renderer`)}const scores=perseusScore.scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=perseusScore.flattenScores(scores);return combinedScore}render(){const apiOptions=this.getApiOptions();const content=this.getContent(this.props,this.state);this.widgetIds=[];if(this.shouldRenderJiptPlaceholder(this.props,this.state)){if(!this.translationIndex){this.translationIndex=getDependencies().rendererTranslationComponents.addComponent(this);}if(!apiOptions.isArticle){return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{"data-perseus-component-index":this.translationIndex,children:content})})}}this._isTwoColumn=false;const parsedMarkdown=this.props.inline?PerseusMarkdown.parseInline(content,{isJipt:this.translationIndex!=null}):PerseusMarkdown.parse(content,{isJipt:this.translationIndex!=null});if(this.props.linterContext.highlightLint){const fullLinterContext={content:this.props.content,widgets:this.props.widgets,...this.props.linterContext};PerseusLinter__namespace.runLinter(parsedMarkdown,fullLinterContext,true);this._translationLinter.applyLintErrors(parsedMarkdown,[...this.state.translationLintErrors,...this.props.legacyPerseusLint||[]]);}const markdownContents=this.outputMarkdown(parsedMarkdown,{baseElements:apiOptions.baseElements});const className=classNames__default.default({[ClassNames.RENDERER]:true,[ClassNames.RESPONSIVE_RENDERER]:true,[ClassNames.TWO_COLUMN_RENDERER]:this._isTwoColumn});return jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{className:className,children:markdownContents})})}constructor(props){super(props),this._widgetContainers=new Map,this.getApiOptions=()=>{return {...ApiOptions.defaults,...this.props.apiOptions}},this._getInitialWidgetState=props=>{const allWidgetInfo=perseusCore.applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo}},this._getDefaultWidgetInfo=widgetId=>{const widgetIdParts=Util.rTypeFromWidgetId.exec(widgetId);if(widgetIdParts==null){return {}}return {type:widgetIdParts[1],graded:true,options:{}}},this._getWidgetInfo=widgetId=>{return this.state.widgetInfo[widgetId]||this._getDefaultWidgetInfo(widgetId)},this.renderWidget=(impliedType,id,state)=>{const widgetInfo=this.state.widgetInfo[id];if(widgetInfo&&widgetInfo.alignment==="full-width"){state.foundFullWidth=true;}if(widgetInfo){const type=widgetInfo&&widgetInfo.type||impliedType;let shouldHighlight=false;if(this.props.highlightEmptyWidgets&&this.props.userInput){shouldHighlight=this.emptyWidgets().includes(id);}return jsxRuntimeExports.jsx(WidgetContainer,{id:id,ref:node=>{const containerId=makeContainerId(id);if(node!=null){this._widgetContainers.set(containerId,node);}else {this._widgetContainers.delete(containerId);}},type:type,widgetProps:this.getWidgetProps(id),shouldHighlight:shouldHighlight,linterContext:PerseusLinter__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.findInternalWidgets=filterCriterion=>{let filterFunc;if(typeof filterCriterion==="string"){if(filterCriterion.indexOf(" ")!==-1){const widgetId=filterCriterion;filterFunc=(id,widgetInfo,widget)=>id===widgetId;}else {const widgetType=filterCriterion;filterFunc=(id,widgetInfo,widget)=>{return widgetInfo.type===widgetType};}}else {filterFunc=filterCriterion;}const results=this.widgetIds.filter(id=>{const widgetInfo=this._getWidgetInfo(id);const widget=this.getWidgetInstance(id);return filterFunc(id,widgetInfo,widget)}).map(this.getWidgetInstance);return results},this.findWidgets=filterCriterion=>{return [...this.findInternalWidgets(filterCriterion),...this.props.findExternalWidgets(filterCriterion)]},this.getWidgetInstance=id=>{const ref=this._widgetContainers.get(makeContainerId(id));if(!ref){return null}return ref.getWidget()},this._onWidgetFocus=(id,focusPath=[])=>{if(!___default.default.isArray(focusPath)){throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),perseusCore.Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!___default.default.isEqual(fullPath,blurringFocusPath)){return}___default.default.defer(()=>{if(___default.default.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.getContent=(props,state)=>{return state.jiptContent||props.content},this.shouldRenderJiptPlaceholder=(props,state)=>{return getDependencies().JIPT.useJIPT&&state.jiptContent==null&&props.content.indexOf("crwdns")!==-1},this.replaceJiptContent=(content,paragraphIndex)=>{if(paragraphIndex==null){this.setState({jiptContent:content});}else {const codeFenceRegex=/^\s*(`{3,}|~{3,})\s*(\S+)?\s*\n([\s\S]+?)\s*\1\s*$/;if(codeFenceRegex.test(content));else if(/\S\n\s*\n\S/.test(content)){content="$\\large{\\red{\\text{Please translate each "+"paragraph to a single paragraph.}}}$";}else if(/^\s*$/.test(content)){content="$\\large{\\red{\\text{Translated paragraph is "+"currently empty}}}$";}const allContent=this.getContent(this.props,this.state);const paragraphs=JiptParagraphs.parseToArray(allContent);paragraphs[paragraphIndex]=content;this.setState({jiptContent:JiptParagraphs.joinFromArray(paragraphs)});}},this.outputMarkdown=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;state.paragraphIndex=i;const nodeOut=this.outputMarkdown(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}this._foundTextNodes=false;state.foundFullWidth=false;const output=this.outputNested(ast,state);let className;if(this.translationIndex!=null){className=null;}else {className=classNames__default.default({"perseus-paragraph-centered":!this._foundTextNodes,"perseus-paragraph-full-width":state.foundFullWidth&&ast.content.length===1});}return jsxRuntimeExports.jsx(QuestionParagraph,{className:className,translationIndex:this.translationIndex,paragraphIndex:state.paragraphIndex,inline:this.props.inline,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:output})},state.key)},this.outputNested=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;const nodeOut=this.outputNested(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}return this.outputNode(ast,this.outputNested,state)},this.outputNode=(node,nestedOutput,state)=>{const apiOptions=this.getApiOptions();const imagePlaceholder=apiOptions.imagePlaceholder;if(node.type==="widget"){const widgetPlaceholder=apiOptions.widgetPlaceholder;if(widgetPlaceholder){return widgetPlaceholder}this._foundTextNodes=true;if(this.widgetIds.includes(node.id)){return jsxRuntimeExports.jsx("span",{className:"renderer-widget-error",children:["Widget [[","☃"," ",node.id,"]] already exists."].join("")},state.key)}this.widgetIds.push(node.id);return this.renderWidget(node.widgetType,node.id,state)}if(node.type==="blockMath"){const content=preprocessTex(node.content);const innerStyle={overflowX:"auto",overflowY:"hidden",paddingTop:10,paddingBottom:10,marginTop:-10,marginBottom:-10};if(apiOptions.isMobile){const margin=16;const outerStyle={marginLeft:-16,marginRight:-16};const horizontalPadding={paddingLeft:margin,paddingRight:margin};const mobileInnerStyle={...innerStyle,...styles$z.mobileZoomableParentFix};return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",style:outerStyle,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:{...mobileInnerStyle,...horizontalPadding},children:jsxRuntimeExports.jsx(ZoomableTeX,{children:content})})})},state.key)}return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:innerStyle,children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{setAssetStatus:setAssetStatus,children:content})})})})},state.key)}if(node.type==="math"){const tex=node.content;return jsxRuntimeExports.jsx("span",{style:{whiteSpace:"nowrap"},children:jsxRuntimeExports.jsxs(ErrorBoundary,{children:[jsxRuntimeExports.jsx("span",{}),jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{onRender:this.props.onRender,setAssetStatus:setAssetStatus,children:tex})}),jsxRuntimeExports.jsx("span",{})]})},state.key)}if(node.type==="image"){if(imagePlaceholder){return imagePlaceholder}const extraAttrs=___default.default.has(this.props.images,node.target)?this.props.images[node.target]:null;const responsive=!state.inTable;return jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{allowZoom:true,setAssetStatus:setAssetStatus,src:PerseusMarkdown.sanitizeUrl(node.target),alt:node.alt,title:node.title,responsive:responsive,onUpdate:this.props.onRender,zoomToFullSizeOnMobile:apiOptions.isMobile&&apiOptions.isArticle,...extraAttrs})})},state.key)}if(node.type==="columns"){this._isTwoColumn=true;return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)}if(node.type==="text"){if(rContainsNonWhitespace.test(node.content)){this._foundTextNodes=true;}if(imagePlaceholder&&rImageURL.test(node.content)){return imagePlaceholder}return node.content}if(node.type==="table"||node.type==="titledTable"){const output=PerseusMarkdown.ruleOutput(node,nestedOutput,{...state,isMobile:apiOptions.isMobile,inTable:true});if(!apiOptions.isMobile){return output}const outerStyle={marginLeft:-16,marginRight:-16};const innerStyle={paddingLeft:0,paddingRight:0};const mobileInnerStyle={...innerStyle,...styles$z.mobileZoomableParentFix};const wrappedOutput=jsxRuntimeExports.jsx("div",{style:{...mobileInnerStyle,overflowX:"auto"},children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(Zoomable,{animateHeight:true,children:output})})});return jsxRuntimeExports.jsx("div",{style:outerStyle,children:wrappedOutput})}return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)},this.handleRender=prevProps=>{const onRender=this.props.onRender;const oldOnRender=prevProps.onRender;if(onRender!==noopOnRender||oldOnRender!==noopOnRender){const $images=$__default.default(ReactDOM__namespace.default.findDOMNode(this)).find("img");if(oldOnRender!==noopOnRender){$images.off("load",oldOnRender);}if(onRender!==noopOnRender){$images.on("load",onRender);}}onRender();},this._setCurrentFocus=path=>{const apiOptions=this.getApiOptions();if(!isIdPathPrefix(path,this._currentFocus)){const prevFocus=this._currentFocus;if(prevFocus){this.blurPath(prevFocus);}this._currentFocus=path;apiOptions.onFocusChange(this._currentFocus,prevFocus);}},this.focus=()=>{let id;let focusResult;for(let i=0;i<this.widgetIds.length;i++){const widgetId=this.widgetIds[i];const widget=this.getWidgetInstance(widgetId);const widgetFocusResult=widget?.focus?.();if(widgetFocusResult){id=widgetId;focusResult=widgetFocusResult;break}}if(id){let path;if(typeof focusResult==="object"){path=[id].concat(focusResult.path||[]);Log.error("Renderer received a focus result of type 'object' "+"instead of the expected type 'boolean'",perseusCore.Errors.Internal,{loggedMetadata:{focusResult:JSON.stringify(focusResult)}});}else {path=[id];}this._setCurrentFocus(path);return true}},this.getDOMNodeForPath=path=>{const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){const container=this._widgetContainers.get(makeContainerId(widgetId));if(container){return ReactDOM__namespace.default.findDOMNode(container)}return ReactDOM__namespace.default.findDOMNode(widget)}},this.getInputPaths=()=>{const inputPaths=[];this.widgetIds.forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getInputPaths){const widgetInputPaths=widget.getInputPaths();widgetInputPaths.forEach(inputPath=>{const relativeInputPath=[widgetId].concat(inputPath);inputPaths.push(relativeInputPath);});}});return inputPaths},this.focusPath=path=>{if(___default.default.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!___default.default.isEqual(this._currentFocus,path)){return}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget){const blurWidget=this.getWidgetInstance(widgetId);blurWidget?.blurInputPath?.(interWidgetPath);}},this.blur=()=>{if(this._currentFocus){this.blurPath(this._currentFocus);}},this.serialize=()=>{const state={};___default.default.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!___default.default.isEmpty(s)){state[id]=s;}},this);return state},this.getWidgetIds=()=>{return this.widgetIds},this.handletranslationLintErrors=lintErrors=>{if(!this._isMounted){return}this.setState({translationLintErrors:lintErrors});};this._translationLinter=new TranslationLinter;this.state={jiptContent:null,translationLintErrors:[],...this._getInitialWidgetState(props)};}}Renderer.contextType=PerseusI18nContext;Renderer.defaultProps={content:"",widgets:{},images:{},showSolutions:"none",onRender:noopOnRender,findExternalWidgets:()=>[],alwaysUpdate:false,reviewMode:false,linterContext:PerseusLinter__namespace.linterContextDefault};const styles$z={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
|
|
1730
1731
|
|
|
1731
1732
|
const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;const InputWithExamples=React.forwardRef(function InputWithExamples({shouldShowExamples=true,onFocus=()=>{},onBlur=()=>{},disabled=false,linterContext=PerseusLinter__namespace.linterContextDefault,className="",...props},ref){const context=React__namespace.useContext(PerseusI18nContext);const inputRef=React__namespace.useRef(null);const[inputFocused,setInputFocused]=React__namespace.useState(false);const id=React.useId();const ariaId=`aria-for-${id}`;React.useImperativeHandle(ref,()=>({current:inputRef.current,focus:()=>{if(inputRef.current){inputRef.current.focus();}},blur:()=>{if(inputRef.current){inputRef.current.blur();}}}));const getInputClassName=()=>{let inputClassName=ClassNames.INPUT;if(inputFocused){inputClassName+=" "+ClassNames.FOCUSED;}if(className){inputClassName+=" "+className;}return inputClassName};const handleFocus=()=>{onFocus();setInputFocused(true);};const handleBlur=()=>{onBlur();setInputFocused(false);};const renderInput=()=>{const examplesAria=shouldShowExamples?`${props.examples[0]}
|
|
1732
1733
|
${props.examples.slice(1).join(", or\n")}`.replace(/\*/g,"").replace(/\$/g,"").replace(/\\ \\text{pi}/g," pi").replace(/\\ /g," and "):"";const inputProps={id:id,"aria-describedby":shouldShowExamples?ariaId:undefined,ref:inputRef,className:getInputClassName(),labelText:props.labelText,value:props.value,onFocus:handleFocus,onBlur:handleBlur,disabled:disabled,style:props.style,onChange:props.onChange,onTouchStart:captureScratchpadTouchStart$1,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",spellCheck:"false"};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(TextInput,{...inputProps}),jsxRuntimeExports.jsx("span",{id:ariaId,style:{display:"none"},children:examplesAria})]})};const renderTooltipContent=()=>{return jsxRuntimeExports.jsx(Tooltip.TooltipContent,{children:jsxRuntimeExports.jsx("div",{id:id,className:"input-with-examples-tooltip",children:jsxRuntimeExports.jsx(Renderer,{content:examplesContent,linterContext:PerseusLinter__namespace.pushContextStack(linterContext,"input-with-examples"),strings:context.strings})})})};const examplesContent=props.examples.length<=2?props.examples.join(" "):props.examples.map((example,index)=>{return index===0&&example.startsWith("**")?`${example}
|
|
@@ -2045,9 +2046,9 @@ const GRAPH_LEFT_MARGIN=20;const MafsGraph=props=>{const{state,dispatch,labels,l
|
|
|
2045
2046
|
|
|
2046
2047
|
function mafsStateToInteractiveGraph(state,originalGraph){switch(state.type){case "angle":invariant__default.default(originalGraph.type==="angle");return {...originalGraph,coords:state.coords};case "quadratic":invariant__default.default(originalGraph.type==="quadratic");return {...originalGraph,coords:state.coords};case "circle":invariant__default.default(originalGraph.type==="circle");return {...originalGraph,center:state.center,radius:getRadius(state)};case "linear":invariant__default.default(originalGraph.type==="linear");return {...originalGraph,coords:state.coords};case "ray":invariant__default.default(originalGraph.type==="ray");return {...originalGraph,coords:state.coords};case "sinusoid":invariant__default.default(originalGraph.type==="sinusoid");return {...originalGraph,coords:state.coords};case "segment":invariant__default.default(originalGraph.type==="segment");return {...originalGraph,coords:state.coords};case "linear-system":invariant__default.default(originalGraph.type==="linear-system");return {...originalGraph,coords:state.coords};case "polygon":invariant__default.default(originalGraph.type==="polygon");return {...originalGraph,coords:state.coords};case "point":invariant__default.default(originalGraph.type==="point");return {...originalGraph,coords:state.coords};case "exponential":invariant__default.default(originalGraph.type==="exponential");return {...originalGraph,coords:state.coords,asymptote:state.asymptote};case "none":invariant__default.default(originalGraph.type==="none");return {...originalGraph};case "absolute-value":invariant__default.default(originalGraph.type==="absolute-value");return {...originalGraph,coords:state.coords};case "tangent":invariant__default.default(originalGraph.type==="tangent");return {...originalGraph,coords:state.coords};case "logarithm":invariant__default.default(originalGraph.type==="logarithm");return {...originalGraph,coords:state.coords,asymptote:state.asymptote};case "vector":invariant__default.default(originalGraph.type==="vector");return {...originalGraph,coords:state.coords};default:throw new wonderStuffCore.UnreachableCaseError(state)}}
|
|
2047
2048
|
|
|
2048
|
-
const StatefulMafsGraph=React__namespace.forwardRef(function StatefulMafsGraphWithRef(props,ref){const{onChange,graph}=props;const[state,dispatch]=React__namespace.useReducer(interactiveGraphReducer,props,initializeGraphState);React.useImperativeHandle(ref,()=>({getUserInput:()=>getGradableGraph(state,graph)}));const prevState=React.useRef(state);React.useEffect(()=>{if(prevState.current!==state){onChange(mafsStateToInteractiveGraph(state,graph));}prevState.current=state;},[onChange,state,graph]);const[xSnap,ySnap]=props.snapStep;React.useEffect(()=>{dispatch(changeSnapStep([xSnap,ySnap]));},[dispatch,xSnap,ySnap]);const[[xMinRange,xMaxRange],[yMinRange,yMaxRange]]=props.range;React.useEffect(()=>{dispatch(changeRange([[xMinRange,xMaxRange],[yMinRange,yMaxRange]]));},[dispatch,xMinRange,xMaxRange,yMinRange,yMaxRange]);const numSegments=graph.type==="segment"?graph.numSegments:null;const numPoints=graph.type==="point"?graph.numPoints:null;const numSides=graph.type==="polygon"?graph.numSides:null;const snapTo=graph.type==="polygon"?graph.snapTo:null;const showAngles=graph.type==="polygon"||graph.type==="angle"?graph.showAngles:null;const allowReflexAngles=graph.type==="angle"?graph.allowReflexAngles:null;const showSides=graph.type==="polygon"?graph.showSides:null;const startCoords="startCoords"in graph?graph.startCoords:undefined;const originalPropsRef=React.useRef(props);const latestPropsRef=wonderBlocksCore.useLatestRef(props);React.useEffect(()=>{if(latestPropsRef.current!==originalPropsRef.current){dispatch(reinitialize(latestPropsRef.current));}},[graph.type,numPoints,numSegments,numSides,snapTo,showAngles,showSides,latestPropsRef,startCoords,allowReflexAngles]);if(props.static&&props.correct){return jsxRuntimeExports.jsx(MafsGraph,{...props,state:initializeGraphState({...props,graph:props.correct}),dispatch:dispatch})}return jsxRuntimeExports.jsx(MafsGraph,{...props,state:state,dispatch:dispatch})});
|
|
2049
|
+
const StatefulMafsGraph=React__namespace.forwardRef(function StatefulMafsGraphWithRef(props,ref){const{onChange,graph}=props;const[state,dispatch]=React__namespace.useReducer(interactiveGraphReducer,props,initializeGraphState);React.useImperativeHandle(ref,()=>({getUserInput:()=>getGradableGraph(state,graph)}));const prevState=React.useRef(state);React.useEffect(()=>{if(prevState.current!==state){onChange(mafsStateToInteractiveGraph(state,graph));}prevState.current=state;},[onChange,state,graph]);const[xSnap,ySnap]=props.snapStep;React.useEffect(()=>{dispatch(changeSnapStep([xSnap,ySnap]));},[dispatch,xSnap,ySnap]);const[[xMinRange,xMaxRange],[yMinRange,yMaxRange]]=props.range;React.useEffect(()=>{dispatch(changeRange([[xMinRange,xMaxRange],[yMinRange,yMaxRange]]));},[dispatch,xMinRange,xMaxRange,yMinRange,yMaxRange]);const numSegments=graph.type==="segment"?graph.numSegments:null;const numPoints=graph.type==="point"?graph.numPoints:null;const numSides=graph.type==="polygon"?graph.numSides:null;const snapTo=graph.type==="polygon"?graph.snapTo:null;const showAngles=graph.type==="polygon"||graph.type==="angle"?graph.showAngles:null;const allowReflexAngles=graph.type==="angle"?graph.allowReflexAngles:null;const showSides=graph.type==="polygon"?graph.showSides:null;const startCoords="startCoords"in graph?graph.startCoords:undefined;const originalPropsRef=React.useRef(props);const latestPropsRef=wonderBlocksCore.useLatestRef(props);React.useEffect(()=>{if(latestPropsRef.current!==originalPropsRef.current){dispatch(reinitialize(latestPropsRef.current));}},[graph.type,numPoints,numSegments,numSides,snapTo,showAngles,showSides,latestPropsRef,startCoords,allowReflexAngles]);if(props.static&&props.correct&&props.graded!==false){return jsxRuntimeExports.jsx(MafsGraph,{...props,state:initializeGraphState({...props,graph:props.correct}),dispatch:dispatch})}return jsxRuntimeExports.jsx(MafsGraph,{...props,state:state,dispatch:dispatch})});
|
|
2049
2050
|
|
|
2050
|
-
const{getClockwiseAngle}=kmath.angles;const{getSinusoidCoefficients,getTangentCoefficients,getQuadraticCoefficients,getExponentialCoefficients,getLogarithmCoefficients}=kmath.coefficients;const{getLineEquation,getLineIntersectionString,magnitude,vector}=kmath.geometry;const defaultBackgroundImage={url:null};const UNLIMITED="unlimited";function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}const makeInvalidTypeError=(functionName,graphType)=>{return new perseusCore.PerseusError(`${functionName} called but current graph type is not a '${graphType}'`,perseusCore.Errors.NotAllowed,{metadata:{graphType}})};class InteractiveGraph extends React__namespace.Component{getUserInput(){if(this.mafsRef.current?.getUserInput){return this.mafsRef.current.getUserInput()}throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered",perseusCore.Errors.NotAllowed)}getPromptJSON(){return getPromptJSON$b(this.props,this.getUserInput())}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,graph:this.props.userInput}}render(){const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,box[0]);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const mafsProps={...this.props,graph:this.props.userInput,onChange:()=>this.props.handleUserInput(this.mafsRef.current?.getUserInput())};return jsxRuntimeExports.jsx(StatefulMafsGraph,{...mafsProps,ref:this.mafsRef,gridStep:gridStep,snapStep:snapStep,box:box,showTooltips:!!this.props.showTooltips,readOnly:this.props.apiOptions?.readOnly,widgetId:this.props.widgetId})}static getLineCoords(graph,props){return graph.coords||InteractiveGraph.pointsFromNormalized(props,[[.25,.75],[.75,.75]])}static getPointCoords(graph,props){const numPoints=graph.numPoints||1;let coords=graph.coords;if(coords){return coords}switch(numPoints){case 1:coords=[graph.coord||[0,0]];break;case 2:coords=[[-5,0],[5,0]];break;case 3:coords=[[-5,0],[0,0],[5,0]];break;case 4:coords=[[-6,0],[-2,0],[2,0],[6,0]];break;case 5:coords=[[-6,0],[-3,0],[0,0],[3,0],[6,0]];break;case 6:coords=[[-5,0],[-3,0],[-1,0],[1,0],[3,0],[5,0]];break;case UNLIMITED:coords=[];break}const range=[[-10,10],[-10,10]];const newCoords=InteractiveGraph.normalizeCoords(coords,range);return InteractiveGraph.pointsFromNormalized(props,newCoords)}static getLinearSystemCoords(graph,props){return graph.coords||___default.default.map([[[.25,.75],[.75,.75]],[[.25,.25],[.75,.25]]],coords=>{return InteractiveGraph.pointsFromNormalized(props,coords)})}static getPolygonCoords(graph,props){if(graph.type!=="polygon"){throw makeInvalidTypeError("toggleShowSides","polygon")}let coords=graph.coords;if(coords){return coords}const n=graph.numSides||3;if(n===UNLIMITED){coords=[];}else {const angle=2*Math.PI/n;const offset=(1/n-1/2)*Math.PI;const radius=graph.snapTo==="sides"?Math.sqrt(3)/3*7:4;coords=___default.default.times(n,function(i){return [radius*Math.cos(i*angle+offset),radius*Math.sin(i*angle+offset)]});}const ranges=[[-10,10],[-10,10]];coords=InteractiveGraph.normalizeCoords(coords,ranges);const snapToGrid=!___default.default.contains(["angles","sides"],graph.snapTo);coords=InteractiveGraph.pointsFromNormalized(props,coords,!snapToGrid);return coords}static getSegmentCoords(graph,props){const coords=graph.coords;if(coords){return coords}const n=graph.numSegments||1;const ys={1:[5],2:[5,-5],3:[5,0,-5],4:[6,2,-2,-6],5:[6,3,0,-3,-6],6:[5,3,1,-1,-3,-5]}[n];const range=[[-10,10],[-10,10]];return ys.map(function(y){let segment=[[-5,y],[5,y]];segment=InteractiveGraph.normalizeCoords(segment,range);segment=InteractiveGraph.pointsFromNormalized(props,segment);return segment})}static getAngleCoords(graph,props){let coords=graph.coords;if(coords){return coords}const snap=graph.snapDegrees||1;let angle=snap;while(angle<20){angle+=snap;}angle=angle*Math.PI/180;const offset=(graph.angleOffsetDeg||0)*Math.PI/180;coords=InteractiveGraph.pointsFromNormalized(props,[[.85,.5],[.5,.5]]);const radius=magnitude(vector(...coords));coords[0]=[coords[1][0]+radius*Math.cos(offset),coords[1][1]+radius*Math.sin(offset)];coords[2]=[coords[1][0]+radius*Math.cos(angle+offset),coords[1][1]+radius*Math.sin(angle+offset)];return coords}static normalizeCoords(coordsList,ranges){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const extent=ranges[i][1]-ranges[i][0];return (coord+ranges[i][1])/extent})})}static getEquationString(props){const type=props.userInput.type;switch(type){case "none":return InteractiveGraph.getNoneEquationString();case "linear":return InteractiveGraph.getLinearEquationString(props);case "quadratic":return InteractiveGraph.getQuadraticEquationString(props);case "sinusoid":return InteractiveGraph.getSinusoidEquationString(props);case "circle":return InteractiveGraph.getCircleEquationString(props);case "linear-system":return InteractiveGraph.getLinearSystemEquationString(props);case "point":return InteractiveGraph.getPointEquationString(props);case "segment":return InteractiveGraph.getSegmentEquationString(props);case "ray":return InteractiveGraph.getRayEquationString(props);case "polygon":return InteractiveGraph.getPolygonEquationString(props);case "angle":return InteractiveGraph.getAngleEquationString(props);case "absolute-value":return InteractiveGraph.getAbsoluteValueEquationString(props);case "exponential":return InteractiveGraph.getExponentialEquationString(props);case "tangent":return InteractiveGraph.getTangentEquationString(props);case "logarithm":return InteractiveGraph.getLogarithmEquationString(props);case "vector":return InteractiveGraph.getVectorEquationString(props);default:throw new wonderStuffCore.UnreachableCaseError(type)}}static pointsFromNormalized(props,coordsList,noSnap){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const range=props.range[i];if(noSnap){return range[0]+(range[1]-range[0])*coord}const step=props.step[i];const nSteps=numSteps(range,step);const tick=Math.round(coord*nSteps);return range[0]+step*tick})})}static getNoneEquationString(){return ""}static getLinearEquationString(props){const coords=InteractiveGraph.getLineCoords(props.userInput,props);if(perseusCore.approximateEqual(coords[0][0],coords[1][0])){return "x = "+coords[0][0].toFixed(3)}const m=(coords[1][1]-coords[0][1])/(coords[1][0]-coords[0][0]);const b=coords[0][1]-m*coords[0][0];if(perseusCore.approximateEqual(m,0)){return "y = "+b.toFixed(3)}return "y = "+m.toFixed(3)+"x + "+b.toFixed(3)}static getCurrentQuadraticCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultQuadraticCoords(props);return getQuadraticCoefficients(coords)}static defaultQuadraticCoords(props){const coords=[[.25,.75],[.5,.25],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getQuadraticEquationString(props){const coeffs=InteractiveGraph.getCurrentQuadraticCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"x^2 + "+coeffs[1].toFixed(3)+"x + "+coeffs[2].toFixed(3)}static getCurrentSinusoidCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultSinusoidCoords(props);return getSinusoidCoefficients(coords)}static defaultSinusoidCoords(props){const coords=[[.5,.5],[.65,.6]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getSinusoidEquationString(props){const coeffs=InteractiveGraph.getCurrentSinusoidCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"sin("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}static defaultExponentialCoords(props){const coords=[[.5,.55],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords,true)}static getExponentialEquationString(props){const coords=props.userInput.coords||InteractiveGraph.defaultExponentialCoords(props);const asymptote=props.userInput.asymptote??0;const coeffs=getExponentialCoefficients(coords,asymptote);if(coeffs==null){return "y = e^x"}return "y = "+coeffs.a.toFixed(3)+"e^("+coeffs.b.toFixed(3)+"x) + "+coeffs.c.toFixed(3)}static defaultLogarithmCoords(props){const coords=[[.55,.55],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords,true)}static getLogarithmEquationString(props){const coords=props.userInput.coords||InteractiveGraph.defaultLogarithmCoords(props);const asymptote=props.userInput.asymptote??0;const coeffs=getLogarithmCoefficients(coords,asymptote);if(coeffs==null){return "y = ln(x)"}const cStr=coeffs.c===0?"x":coeffs.c<0?"x - "+Math.abs(coeffs.c).toFixed(3):"x + "+coeffs.c.toFixed(3);return "y = "+coeffs.a.toFixed(3)+"ln("+coeffs.b.toFixed(3)+cStr+")"}static getAbsoluteValueEquationString(props){const userInput=props.userInput;if(userInput.type!=="absolute-value"||!userInput.coords){return ""}const coeffs=getAbsoluteValueCoefficients(userInput.coords);if(coeffs===undefined){return ""}const{m,h,v}=coeffs;return "y = "+m.toFixed(3)+"|x - "+h.toFixed(3)+"| + "+v.toFixed(3)}static getCurrentTangentCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultTangentCoords(props);return getTangentCoefficients(coords)}static defaultTangentCoords(props){const coords=[[.5,.5],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getTangentEquationString(props){const coeffs=InteractiveGraph.getCurrentTangentCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"tan("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}static getCircleEquationString(props){const graph=props.userInput;const center=graph.center||[0,0];const radius=graph.radius||2;return "center ("+center[0]+", "+center[1]+"), radius "+radius}static getLinearSystemEquationString(props){const coords=InteractiveGraph.getLinearSystemCoords(props.userInput,props);return "\n"+getLineEquation(coords[0][0],coords[0][1])+"\n"+getLineEquation(coords[1][0],coords[1][1])+"\n"+getLineIntersectionString(coords[0],coords[1])}static getPointEquationString(props){if(props.userInput.type!=="point"){throw makeInvalidTypeError("getPointEquationString","point")}const coords=InteractiveGraph.getPointCoords(props.userInput,props);return coords.map(function(coord){return "("+coord[0]+", "+coord[1]+")"}).join(", ")}static getSegmentEquationString(props){if(props.userInput.type!=="segment"){throw makeInvalidTypeError("getSegmentEquationString","segment")}const segments=InteractiveGraph.getSegmentCoords(props.userInput,props);return ___default.default.map(segments,function(segment){return "["+___default.default.map(segment,function(coord){return "("+coord.join(", ")+")"}).join(" ")+"]"}).join(" ")}static getRayEquationString(props){if(props.userInput.type!=="ray"){throw makeInvalidTypeError("createPointForPolygonType","ray")}const coords=InteractiveGraph.getLineCoords(props.userInput,props);const a=coords[0];const b=coords[1];let eq=InteractiveGraph.getLinearEquationString(props);if(a[0]>b[0]){eq+=" (for x <= "+a[0].toFixed(3)+")";}else if(a[0]<b[0]){eq+=" (for x >= "+a[0].toFixed(3)+")";}else if(a[1]>b[1]){eq+=" (for y <= "+a[1].toFixed(3)+")";}else {eq+=" (for y >= "+a[1].toFixed(3)+")";}return eq}static getPolygonEquationString(props){if(props.userInput.type!=="polygon"){throw makeInvalidTypeError("getPolygonEquationString","polygon")}const coords=InteractiveGraph.getPolygonCoords(props.userInput,props);return ___default.default.map(coords,function(coord){return "("+coord.join(", ")+")"}).join(" ")}static getAngleEquationString(props){if(props.userInput.type!=="angle"){throw makeInvalidTypeError("getAngleEquationString","angle")}const coords=InteractiveGraph.getAngleCoords(props.userInput,props);const allowReflexAngles=props.userInput.allowReflexAngles;const angle=getClockwiseAngle(coords,allowReflexAngles);return angle.toFixed(0)+"° angle"+" at ("+coords[1].join(", ")+")"}static getVectorEquationString(props){if(props.userInput.type!=="vector"){throw makeInvalidTypeError("getVectorEquationString","vector")}const coords=props.userInput.coords;if(!coords){return ""}const[tail,tip]=coords;const dx=tip[0]-tail[0];const dy=tip[1]-tail[1];return `\u27E8${dx.toFixed(3)}, ${dy.toFixed(3)}\u27E9`}constructor(...args){super(...args),this.mafsRef=React__namespace.createRef();}}InteractiveGraph.defaultProps={labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true},step:[1,1],backgroundImage:defaultBackgroundImage,markings:"graph",showTooltips:false,showProtractor:false,userInput:{type:"linear"}};function getUserInputFromSerializedState$8(serializedState){return serializedState.graph}function getStartUserInput$8(options){return options.graph}function getCorrectUserInput$4(options){return options.correct}var InteractiveGraph$1 = {name:"interactive-graph",displayName:"Interactive graph",widget:InteractiveGraph,getStartUserInput: getStartUserInput$8,getCorrectUserInput: getCorrectUserInput$4,getUserInputFromSerializedState: getUserInputFromSerializedState$8};
|
|
2051
|
+
const{getClockwiseAngle}=kmath.angles;const{getSinusoidCoefficients,getTangentCoefficients,getQuadraticCoefficients,getExponentialCoefficients,getLogarithmCoefficients}=kmath.coefficients;const{getLineEquation,getLineIntersectionString,magnitude,vector}=kmath.geometry;const defaultBackgroundImage={url:null};const UNLIMITED="unlimited";function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}const makeInvalidTypeError=(functionName,graphType)=>{return new perseusCore.PerseusError(`${functionName} called but current graph type is not a '${graphType}'`,perseusCore.Errors.NotAllowed,{metadata:{graphType}})};class InteractiveGraph extends React__namespace.Component{getUserInput(){if(this.mafsRef.current?.getUserInput){return this.mafsRef.current.getUserInput()}throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered",perseusCore.Errors.NotAllowed)}getPromptJSON(){return getPromptJSON$b(this.props,this.getUserInput())}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,graph:this.props.userInput}}render(){const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,box[0]);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const mafsProps={...this.props,graph:this.props.userInput,onChange:()=>this.props.handleUserInput(this.mafsRef.current?.getUserInput())};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[this.props.graded===false&&jsxRuntimeExports.jsx("p",{children:this.context.strings.ungradedInteractiveGraph}),jsxRuntimeExports.jsx(StatefulMafsGraph,{...mafsProps,ref:this.mafsRef,gridStep:gridStep,snapStep:snapStep,box:box,showTooltips:!!this.props.showTooltips,readOnly:this.props.apiOptions?.readOnly,widgetId:this.props.widgetId,graded:this.props.graded})]})}static getLineCoords(graph,props){return graph.coords||InteractiveGraph.pointsFromNormalized(props,[[.25,.75],[.75,.75]])}static getPointCoords(graph,props){const numPoints=graph.numPoints||1;let coords=graph.coords;if(coords){return coords}switch(numPoints){case 1:coords=[graph.coord||[0,0]];break;case 2:coords=[[-5,0],[5,0]];break;case 3:coords=[[-5,0],[0,0],[5,0]];break;case 4:coords=[[-6,0],[-2,0],[2,0],[6,0]];break;case 5:coords=[[-6,0],[-3,0],[0,0],[3,0],[6,0]];break;case 6:coords=[[-5,0],[-3,0],[-1,0],[1,0],[3,0],[5,0]];break;case UNLIMITED:coords=[];break}const range=[[-10,10],[-10,10]];const newCoords=InteractiveGraph.normalizeCoords(coords,range);return InteractiveGraph.pointsFromNormalized(props,newCoords)}static getLinearSystemCoords(graph,props){return graph.coords||___default.default.map([[[.25,.75],[.75,.75]],[[.25,.25],[.75,.25]]],coords=>{return InteractiveGraph.pointsFromNormalized(props,coords)})}static getPolygonCoords(graph,props){if(graph.type!=="polygon"){throw makeInvalidTypeError("toggleShowSides","polygon")}let coords=graph.coords;if(coords){return coords}const n=graph.numSides||3;if(n===UNLIMITED){coords=[];}else {const angle=2*Math.PI/n;const offset=(1/n-1/2)*Math.PI;const radius=graph.snapTo==="sides"?Math.sqrt(3)/3*7:4;coords=___default.default.times(n,function(i){return [radius*Math.cos(i*angle+offset),radius*Math.sin(i*angle+offset)]});}const ranges=[[-10,10],[-10,10]];coords=InteractiveGraph.normalizeCoords(coords,ranges);const snapToGrid=!___default.default.contains(["angles","sides"],graph.snapTo);coords=InteractiveGraph.pointsFromNormalized(props,coords,!snapToGrid);return coords}static getSegmentCoords(graph,props){const coords=graph.coords;if(coords){return coords}const n=graph.numSegments||1;const ys={1:[5],2:[5,-5],3:[5,0,-5],4:[6,2,-2,-6],5:[6,3,0,-3,-6],6:[5,3,1,-1,-3,-5]}[n];const range=[[-10,10],[-10,10]];return ys.map(function(y){let segment=[[-5,y],[5,y]];segment=InteractiveGraph.normalizeCoords(segment,range);segment=InteractiveGraph.pointsFromNormalized(props,segment);return segment})}static getAngleCoords(graph,props){let coords=graph.coords;if(coords){return coords}const snap=graph.snapDegrees||1;let angle=snap;while(angle<20){angle+=snap;}angle=angle*Math.PI/180;const offset=(graph.angleOffsetDeg||0)*Math.PI/180;coords=InteractiveGraph.pointsFromNormalized(props,[[.85,.5],[.5,.5]]);const radius=magnitude(vector(...coords));coords[0]=[coords[1][0]+radius*Math.cos(offset),coords[1][1]+radius*Math.sin(offset)];coords[2]=[coords[1][0]+radius*Math.cos(angle+offset),coords[1][1]+radius*Math.sin(angle+offset)];return coords}static normalizeCoords(coordsList,ranges){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const extent=ranges[i][1]-ranges[i][0];return (coord+ranges[i][1])/extent})})}static getEquationString(props){const type=props.userInput.type;switch(type){case "none":return InteractiveGraph.getNoneEquationString();case "linear":return InteractiveGraph.getLinearEquationString(props);case "quadratic":return InteractiveGraph.getQuadraticEquationString(props);case "sinusoid":return InteractiveGraph.getSinusoidEquationString(props);case "circle":return InteractiveGraph.getCircleEquationString(props);case "linear-system":return InteractiveGraph.getLinearSystemEquationString(props);case "point":return InteractiveGraph.getPointEquationString(props);case "segment":return InteractiveGraph.getSegmentEquationString(props);case "ray":return InteractiveGraph.getRayEquationString(props);case "polygon":return InteractiveGraph.getPolygonEquationString(props);case "angle":return InteractiveGraph.getAngleEquationString(props);case "absolute-value":return InteractiveGraph.getAbsoluteValueEquationString(props);case "exponential":return InteractiveGraph.getExponentialEquationString(props);case "tangent":return InteractiveGraph.getTangentEquationString(props);case "logarithm":return InteractiveGraph.getLogarithmEquationString(props);case "vector":return InteractiveGraph.getVectorEquationString(props);default:throw new wonderStuffCore.UnreachableCaseError(type)}}static pointsFromNormalized(props,coordsList,noSnap){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const range=props.range[i];if(noSnap){return range[0]+(range[1]-range[0])*coord}const step=props.step[i];const nSteps=numSteps(range,step);const tick=Math.round(coord*nSteps);return range[0]+step*tick})})}static getNoneEquationString(){return ""}static getLinearEquationString(props){const coords=InteractiveGraph.getLineCoords(props.userInput,props);if(perseusCore.approximateEqual(coords[0][0],coords[1][0])){return "x = "+coords[0][0].toFixed(3)}const m=(coords[1][1]-coords[0][1])/(coords[1][0]-coords[0][0]);const b=coords[0][1]-m*coords[0][0];if(perseusCore.approximateEqual(m,0)){return "y = "+b.toFixed(3)}return "y = "+m.toFixed(3)+"x + "+b.toFixed(3)}static getCurrentQuadraticCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultQuadraticCoords(props);return getQuadraticCoefficients(coords)}static defaultQuadraticCoords(props){const coords=[[.25,.75],[.5,.25],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getQuadraticEquationString(props){const coeffs=InteractiveGraph.getCurrentQuadraticCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"x^2 + "+coeffs[1].toFixed(3)+"x + "+coeffs[2].toFixed(3)}static getCurrentSinusoidCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultSinusoidCoords(props);return getSinusoidCoefficients(coords)}static defaultSinusoidCoords(props){const coords=[[.5,.5],[.65,.6]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getSinusoidEquationString(props){const coeffs=InteractiveGraph.getCurrentSinusoidCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"sin("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}static defaultExponentialCoords(props){const coords=[[.5,.55],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords,true)}static getExponentialEquationString(props){const coords=props.userInput.coords||InteractiveGraph.defaultExponentialCoords(props);const asymptote=props.userInput.asymptote??0;const coeffs=getExponentialCoefficients(coords,asymptote);if(coeffs==null){return "y = e^x"}return "y = "+coeffs.a.toFixed(3)+"e^("+coeffs.b.toFixed(3)+"x) + "+coeffs.c.toFixed(3)}static defaultLogarithmCoords(props){const coords=[[.55,.55],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords,true)}static getLogarithmEquationString(props){const coords=props.userInput.coords||InteractiveGraph.defaultLogarithmCoords(props);const asymptote=props.userInput.asymptote??0;const coeffs=getLogarithmCoefficients(coords,asymptote);if(coeffs==null){return "y = ln(x)"}const cStr=coeffs.c===0?"x":coeffs.c<0?"x - "+Math.abs(coeffs.c).toFixed(3):"x + "+coeffs.c.toFixed(3);return "y = "+coeffs.a.toFixed(3)+"ln("+coeffs.b.toFixed(3)+cStr+")"}static getAbsoluteValueEquationString(props){const userInput=props.userInput;if(userInput.type!=="absolute-value"||!userInput.coords){return ""}const coeffs=getAbsoluteValueCoefficients(userInput.coords);if(coeffs===undefined){return ""}const{m,h,v}=coeffs;return "y = "+m.toFixed(3)+"|x - "+h.toFixed(3)+"| + "+v.toFixed(3)}static getCurrentTangentCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultTangentCoords(props);return getTangentCoefficients(coords)}static defaultTangentCoords(props){const coords=[[.5,.5],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getTangentEquationString(props){const coeffs=InteractiveGraph.getCurrentTangentCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"tan("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}static getCircleEquationString(props){const graph=props.userInput;const center=graph.center||[0,0];const radius=graph.radius||2;return "center ("+center[0]+", "+center[1]+"), radius "+radius}static getLinearSystemEquationString(props){const coords=InteractiveGraph.getLinearSystemCoords(props.userInput,props);return "\n"+getLineEquation(coords[0][0],coords[0][1])+"\n"+getLineEquation(coords[1][0],coords[1][1])+"\n"+getLineIntersectionString(coords[0],coords[1])}static getPointEquationString(props){if(props.userInput.type!=="point"){throw makeInvalidTypeError("getPointEquationString","point")}const coords=InteractiveGraph.getPointCoords(props.userInput,props);return coords.map(function(coord){return "("+coord[0]+", "+coord[1]+")"}).join(", ")}static getSegmentEquationString(props){if(props.userInput.type!=="segment"){throw makeInvalidTypeError("getSegmentEquationString","segment")}const segments=InteractiveGraph.getSegmentCoords(props.userInput,props);return ___default.default.map(segments,function(segment){return "["+___default.default.map(segment,function(coord){return "("+coord.join(", ")+")"}).join(" ")+"]"}).join(" ")}static getRayEquationString(props){if(props.userInput.type!=="ray"){throw makeInvalidTypeError("createPointForPolygonType","ray")}const coords=InteractiveGraph.getLineCoords(props.userInput,props);const a=coords[0];const b=coords[1];let eq=InteractiveGraph.getLinearEquationString(props);if(a[0]>b[0]){eq+=" (for x <= "+a[0].toFixed(3)+")";}else if(a[0]<b[0]){eq+=" (for x >= "+a[0].toFixed(3)+")";}else if(a[1]>b[1]){eq+=" (for y <= "+a[1].toFixed(3)+")";}else {eq+=" (for y >= "+a[1].toFixed(3)+")";}return eq}static getPolygonEquationString(props){if(props.userInput.type!=="polygon"){throw makeInvalidTypeError("getPolygonEquationString","polygon")}const coords=InteractiveGraph.getPolygonCoords(props.userInput,props);return ___default.default.map(coords,function(coord){return "("+coord.join(", ")+")"}).join(" ")}static getAngleEquationString(props){if(props.userInput.type!=="angle"){throw makeInvalidTypeError("getAngleEquationString","angle")}const coords=InteractiveGraph.getAngleCoords(props.userInput,props);const allowReflexAngles=props.userInput.allowReflexAngles;const angle=getClockwiseAngle(coords,allowReflexAngles);return angle.toFixed(0)+"° angle"+" at ("+coords[1].join(", ")+")"}static getVectorEquationString(props){if(props.userInput.type!=="vector"){throw makeInvalidTypeError("getVectorEquationString","vector")}const coords=props.userInput.coords;if(!coords){return ""}const[tail,tip]=coords;const dx=tip[0]-tail[0];const dy=tip[1]-tail[1];return `\u27E8${dx.toFixed(3)}, ${dy.toFixed(3)}\u27E9`}constructor(...args){super(...args),this.mafsRef=React__namespace.createRef();}}InteractiveGraph.contextType=PerseusI18nContext;InteractiveGraph.defaultProps={labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true},step:[1,1],backgroundImage:defaultBackgroundImage,markings:"graph",showTooltips:false,showProtractor:false,userInput:{type:"linear"}};function getUserInputFromSerializedState$8(serializedState){return serializedState.graph}function getStartUserInput$8(options){return options.graph}function getCorrectUserInput$4(options){return options.correct}var InteractiveGraph$1 = {name:"interactive-graph",displayName:"Interactive graph",widget:InteractiveGraph,getStartUserInput: getStartUserInput$8,getCorrectUserInput: getCorrectUserInput$4,getUserInputFromSerializedState: getUserInputFromSerializedState$8,supportsUngraded:true};
|
|
2051
2052
|
|
|
2052
2053
|
const bodyXsmallBold={fontFamily:"inherit",fontSize:15,fontWeight:"bold",lineHeight:"22px"};
|
|
2053
2054
|
|
|
@@ -2121,7 +2122,7 @@ var extraWidgets = [CSProgram$1,Categorizer$1,Definition$1,DeprecatedStandin$1,D
|
|
|
2121
2122
|
|
|
2122
2123
|
const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
|
|
2123
2124
|
|
|
2124
|
-
const libName="@khanacademy/perseus";const libVersion="77.
|
|
2125
|
+
const libName="@khanacademy/perseus";const libVersion="77.4.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
2125
2126
|
|
|
2126
2127
|
const apiVersion={major:12,minor:0};
|
|
2127
2128
|
|