@khanacademy/perseus 61.0.2 → 61.1.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/components/button-group.d.ts +5 -0
- package/dist/components/simple-keypad-input.d.ts +2 -1
- package/dist/es/index.css +1 -1
- package/dist/es/index.js +21 -34
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +23 -35
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +16 -4
- package/dist/util/test-utils.d.ts +23 -1
- package/dist/util.d.ts +1 -1
- package/dist/widgets/expression/expression.d.ts +2 -67
- package/dist/widgets/group/group.d.ts +8 -0
- package/dist/widgets/input-number/input-number.d.ts +6 -16
- package/dist/widgets/interactive-graph.d.ts +1 -1
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +1 -1
- package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +1 -1
- package/dist/widgets/matrix/matrix.d.ts +6 -2
- package/dist/widgets/number-line/number-line.d.ts +17 -15
- package/dist/widgets/numeric-input/input-with-examples.d.ts +22 -1
- package/dist/widgets/numeric-input/numeric-input.class.d.ts +2 -2
- package/dist/widgets/numeric-input/numeric-input.d.ts +3 -67
- package/dist/widgets/orderer/orderer.d.ts +4 -10
- package/dist/widgets/plotter/plotter.d.ts +2 -1
- package/package.json +42 -40
package/dist/es/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { PerseusError, Errors, expressionLogic, getDecimalSeparator, approximateDeepEqual, pluck, CoreWidgetRegistry, getUpgradedWidgetOptions, mapObject, passageRefLogic, usesNumCorrect, radioLogic, shuffle, random, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, shuffleMatcher, getMatrixSize, measurerLogic, registerCoreWidgets, upgradeWidgetInfoToLatestVersion, getWidgetIdsFromContentByType } from '@khanacademy/perseus-core';
|
|
2
|
+
export { isFailure, isSuccess, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem } from '@khanacademy/perseus-core';
|
|
1
3
|
import * as React from 'react';
|
|
2
4
|
import React__default, { useContext, forwardRef, useId, useImperativeHandle, useRef, useState, useEffect, createElement, createContext, useLayoutEffect } from 'react';
|
|
3
5
|
import * as KAS from '@khanacademy/kas';
|
|
4
6
|
import { MathInputI18nContext, DesktopKeypad, getCursorContext, CursorContext, getKeyTranslator, createMathField, convertDotToTimesByLocale, mathQuillInstance, KeypadInput, keypadElementPropType } from '@khanacademy/math-input';
|
|
5
|
-
import { PerseusError, Errors, expressionLogic, getDecimalSeparator, approximateDeepEqual, pluck, CoreWidgetRegistry, getUpgradedWidgetOptions, mapObject, passageRefLogic, usesNumCorrect, radioLogic, shuffle, random, GrapherUtil as GrapherUtil$1, lockedFigureColors, lockedFigureFillStyles, approximateEqual, shuffleMatcher, getMatrixSize, measurerLogic, upgradeWidgetInfoToLatestVersion, getWidgetIdsFromContentByType } from '@khanacademy/perseus-core';
|
|
6
|
-
export { isFailure, isSuccess, parseAndMigratePerseusArticle, parseAndMigratePerseusItem, parsePerseusItem } from '@khanacademy/perseus-core';
|
|
7
7
|
import * as PerseusLinter from '@khanacademy/perseus-linter';
|
|
8
8
|
import { linterContextDefault, Rule } from '@khanacademy/perseus-linter';
|
|
9
9
|
import { View, RenderStateRoot, Id, useOnMountEffect, useLatestRef, Text as Text$2 } from '@khanacademy/wonder-blocks-core';
|
|
@@ -38,6 +38,7 @@ import { vec, Coordinates, Ellipse, Plot as Plot$2, Line as Line$4, Point as Poi
|
|
|
38
38
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
39
39
|
import questionIcon from '@phosphor-icons/core/regular/question.svg';
|
|
40
40
|
import { useDrag } from '@use-gesture/react';
|
|
41
|
+
import invariant from 'tiny-invariant';
|
|
41
42
|
import Switch from '@khanacademy/wonder-blocks-switch';
|
|
42
43
|
import Pill from '@khanacademy/wonder-blocks-pill';
|
|
43
44
|
import { Popper } from 'react-popper';
|
|
@@ -1459,7 +1460,7 @@ const defaultContext$2={assetStatuses:{},setAssetStatus:(assetKey,loaded)=>{}};c
|
|
|
1459
1460
|
|
|
1460
1461
|
const svgLabelsRegex=/^web\+graphie:/;const svgLocalLabelsRegex$1=/^file\+graphie:/;function getRealImageUrl(graphieUrl){if(isLabeledSVG(graphieUrl)){return getSvgUrl(graphieUrl)}return graphieUrl}function isLabeledSVG(graphieUrl){return svgLabelsRegex.test(graphieUrl)||svgLocalLabelsRegex$1.test(graphieUrl)}function getBaseUrl(graphieUrl){return graphieUrl.replace(svgLabelsRegex,"https:").replace(svgLocalLabelsRegex$1,"file:")}function getSvgUrl(graphieUrl){return getBaseUrl(graphieUrl)+".svg"}function getDataUrl(graphieUrl){return getBaseUrl(graphieUrl)+"-data.json"}async function getImageSizeModern(url){const image=new Image;return new Promise((resolve,reject)=>{image.onload=()=>{resolve([image.naturalWidth,image.naturalHeight]);};image.onerror=reject;image.src=getRealImageUrl(url);})}
|
|
1461
1462
|
|
|
1462
|
-
let supportsPassive=false;const nestedMap$2=function(children,func,context){if(Array.isArray(children)){return _.map(children,function(child){return nestedMap$2(child,func)})}return func.call(context,children)};function inputPathsEqual(a,b){if(a==null||b==null){return a==null===(b==null)}return a.length===b.length&&a.every((item,index)=>{return b[index]===item})}const rWidgetRule=/^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;const rTypeFromWidgetId=/^([a-z-]+) ([0-9]+)$/;const rWidgetParts=new RegExp(rWidgetRule.source+"$");const snowman="☃";const split="x".split(/(.)/g).length?function(str,r){return str.split(r)}:function(str,r){const output=[];let lastIndex=r.lastIndex=0;let match;while(match=r.exec(str)){const m=match;output.push(str.slice(lastIndex,m.index));output.push(...m.slice(1));lastIndex=m.index+m[0].length;}output.push(str.slice(lastIndex));return output};function firstNumericalParse$1(text){let first;const val=KhanAnswerTypes.predicate.createValidatorFunctional(function(ans){first=ans;return true},{simplify:"optional",inexact:true,forms:"integer, proper, improper, pi, log, mixed, decimal"});val(text);return first}function stringArrayOfSize
|
|
1463
|
+
let supportsPassive=false;const nestedMap$2=function(children,func,context){if(Array.isArray(children)){return _.map(children,function(child){return nestedMap$2(child,func)})}return func.call(context,children)};function inputPathsEqual(a,b){if(a==null||b==null){return a==null===(b==null)}return a.length===b.length&&a.every((item,index)=>{return b[index]===item})}const rWidgetRule=/^\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/;const rTypeFromWidgetId=/^([a-z-]+) ([0-9]+)$/;const rWidgetParts=new RegExp(rWidgetRule.source+"$");const snowman="☃";const split="x".split(/(.)/g).length?function(str,r){return str.split(r)}:function(str,r){const output=[];let lastIndex=r.lastIndex=0;let match;while(match=r.exec(str)){const m=match;output.push(str.slice(lastIndex,m.index));output.push(...m.slice(1));lastIndex=m.index+m[0].length;}output.push(str.slice(lastIndex));return output};function firstNumericalParse$1(text){let first;const val=KhanAnswerTypes.predicate.createValidatorFunctional(function(ans){first=ans;return true},{simplify:"optional",inexact:true,forms:"integer, proper, improper, pi, log, mixed, decimal"});val(text);return first}function stringArrayOfSize(size){return Array(size).fill("")}function stringArrayOfSize2D(opt){const{rows,columns}=opt;const rowArr=stringArrayOfSize(rows);return rowArr.map(()=>stringArrayOfSize(columns))}function gridDimensionConfig(absTickStep,extent,dimensionConstraint,gridStep){const scale=scaleFromExtent(extent,dimensionConstraint);const stepPx=absTickStep*scale;const unityLabel=stepPx>30;return {scale:scale,tickStep:absTickStep/gridStep,unityLabel:unityLabel}}function getGridStep(range,step,boxSize){return _(2).times(function(i){const scale=scaleFromExtent(range[i],boxSize);const gridStep=gridStepFromTickStep(step[i],scale);return gridStep})}function snapStepFromGridStep(gridStep){return [gridStep[0]/2,gridStep[1]/2]}function gridStepFromTickStep(tickStep,scale){const tickWidth=tickStep*scale;const x=tickStep;const y=Math.pow(10,Math.floor(Math.log(x)/Math.LN10));const leadingDigit=Math.floor(x/y);if(tickWidth<25){return tickStep}if(tickWidth<50){if(leadingDigit===5){return tickStep}return tickStep/2}if(leadingDigit===1){return tickStep/2}if(leadingDigit===2){return tickStep/4}if(leadingDigit===5){return tickStep/5}}function scaleFromExtent(extent,dimensionConstraint){const span=extent[1]-extent[0];const scale=dimensionConstraint/span;return scale}function tickStepFromExtent(extent,dimensionConstraint){const span=extent[1]-extent[0];let tickFactor;if(15<span&&span<=20){tickFactor=23;}else if(span>100||span<5){tickFactor=10;}else {tickFactor=16;}const constraintFactor=dimensionConstraint/500;const desiredNumTicks=tickFactor*constraintFactor;return tickStepFromNumTicks(span,desiredNumTicks)}function tickStepFromNumTicks(span,numTicks){let step=Math.pow(10,Math.floor(Math.log(span/numTicks)/Math.LN10));const err=numTicks/span*step;if(err<=.15){step*=10;}else if(err<=.35){step*=5;}else if(err<=.75){step*=2;}return step}const constrainTickStep=(step,range)=>{const span=range[1]-range[0];const numTicks=span/step;if(numTicks<=10){return step}if(numTicks<=20){return step*2}return tickStepFromNumTicks(span,10)};function constrainedTickStepsFromTickSteps(tickSteps,ranges){return [constrainTickStep(tickSteps[0],ranges[0]),constrainTickStep(tickSteps[1],ranges[1])]}function parseQueryString(query){query=query||window.location.search.substring(1);const urlParams={};const a=/\+/g;const r=/([^&=]+)=?([^&]*)/g;const d=function(s){return decodeURIComponent(s.replace(a," "))};let e;while(e=r.exec(query)){const m=e;urlParams[d(m[1])]=d(m[2]);}return urlParams}function updateQueryString$2(uri,key,value){value=encodeURIComponent(value);const re=new RegExp("([?&])"+key+"=.*?(&|$)","i");const separator=uri.indexOf("?")!==-1?"&":"?";if(uri.match(re)){return uri.replace(re,"$1"+key+"="+value+"$2")}return uri+separator+key+"="+value}function strongEncodeURIComponent(str){return encodeURIComponent(str).replace(/['()!]/g,window.escape).replace(/\*/g,"%2A")}const touchHandlers={pointerDown:false,currentTouchIdentifier:null};function resetTouchHandlers(){Object.assign(touchHandlers,{pointerDown:false,currentTouchIdentifier:null});}function extractPointerLocation(event){let touchOrEvent;if(touchHandlers.pointerDown){if(touchHandlers.currentTouchIdentifier!=null){const len=event.changedTouches?event.changedTouches.length:0;for(let i=0;i<len;i++){if(event.changedTouches[i].identifier===touchHandlers.currentTouchIdentifier){touchOrEvent=event.changedTouches[i];}}}else {touchOrEvent=event;}const isEndish=event.type==="touchend"||event.type==="touchcancel";if(touchOrEvent&&isEndish){touchHandlers.pointerDown=false;touchHandlers.currentTouchIdentifier=null;}}else {touchHandlers.pointerDown=true;if(event.changedTouches){touchOrEvent=event.changedTouches[0];touchHandlers.currentTouchIdentifier=touchOrEvent.identifier;}else {touchOrEvent=event;}}if(touchOrEvent){return {left:touchOrEvent.pageX,top:touchOrEvent.pageY}}}const supportsPassiveEvents=()=>{try{const opts=Object.defineProperty({},"passive",{get:function(){supportsPassive=true;}});window.addEventListener("testPassive",null,opts);window.removeEventListener("testPassive",null,opts);}catch{}return supportsPassive};function captureScratchpadTouchStart$4(e){e.stopPropagation();}function getImageSize(url,callback){const img=new Image;img.onload=function(){if(img.width===0&&img.height===0){document.body?.appendChild(img);_.defer(function(){callback(img.clientWidth,img.clientHeight);document.body?.removeChild(img);});}else {callback(img.width,img.height);}};img.src=getRealImageUrl(url);}function getWordBeforeCursor(textarea){const text=textarea.value;const endPos=textarea.selectionStart-1;const startPos=Math.max(text.lastIndexOf("\n",endPos),text.lastIndexOf(" ",endPos))+1;return {string:text.substring(startPos,endPos+1),pos:{start:startPos,end:endPos}}}function moveCursor(textarea,pos){textarea.selectionStart=pos;textarea.selectionEnd=pos;}const textarea={getWordBeforeCursor,moveCursor};const unescapeMathMode$1=label=>label.startsWith("$")&&label.endsWith("$")?label.slice(1,-1):label;const Util={inputPathsEqual,nestedMap: nestedMap$2,rWidgetRule,rTypeFromWidgetId,rWidgetParts,snowman,split,firstNumericalParse: firstNumericalParse$1,stringArrayOfSize,stringArrayOfSize2D,gridDimensionConfig,getGridStep,snapStepFromGridStep,scaleFromExtent,tickStepFromExtent,gridStepFromTickStep,tickStepFromNumTicks,constrainedTickStepsFromTickSteps,parseQueryString,updateQueryString: updateQueryString$2,strongEncodeURIComponent,touchHandlers,resetTouchHandlers,extractPointerLocation,supportsPassiveEvents,captureScratchpadTouchStart: captureScratchpadTouchStart$4,getImageSize,getImageSizeModern:getImageSizeModern,getRealImageUrl:getRealImageUrl,isLabeledSVG:isLabeledSVG,getBaseUrl:getBaseUrl,getSvgUrl:getSvgUrl,getDataUrl:getDataUrl,textarea,unescapeMathMode: unescapeMathMode$1};
|
|
1463
1464
|
|
|
1464
1465
|
const Log={log:(message,extra)=>{getDependencies().Log.log(message,extra);},error:(message,kind,extra)=>{getDependencies().Log.error(message,kind,extra);}};
|
|
1465
1466
|
|
|
@@ -1689,11 +1690,11 @@ class WidgetContainer extends React.Component{componentDidMount(){if(this.state.
|
|
|
1689
1690
|
|
|
1690
1691
|
const rContainsNonWhitespace=/\S/;const rImageURL=/(web\+graphie|https):\/\/[^\s]*/;const noopOnRender=()=>{};const SHOULD_CLEAR_WIDGETS_PROP_LIST=["content","problemNum","widgets"];const makeContainerId=id=>"container:"+id;const isIdPathPrefix=function(prefixArray,wholeArray){if(prefixArray===null||wholeArray===null){return prefixArray===wholeArray}return _.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return _.isEqual(elem,wholeArray[i])}})};class Renderer extends React.Component{componentDidMount(){this._isMounted=true;this.handleRender({});this._currentFocus=null;if(this.props.serializedState){this.restoreSerializedState(this.props.serializedState);}if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(_.pick(this.props,SHOULD_CLEAR_WIDGETS_PROP_LIST),_.pick(nextProps,SHOULD_CLEAR_WIDGETS_PROP_LIST))){this.setState(this._getInitialWidgetState(nextProps));}}shouldComponentUpdate(nextProps,nextState){if(this.props.alwaysUpdate){return true}const stateChanged=!_.isEqual(this.state,nextState);const propsChanged=!_.isEqual(this.props,nextProps);return propsChanged||stateChanged}UNSAFE_componentWillUpdate(nextProps,nextState){const oldJipt=this.shouldRenderJiptPlaceholder(this.props,this.state);const newJipt=this.shouldRenderJiptPlaceholder(nextProps,nextState);const oldContent=this.getContent(this.props,this.state);const newContent=this.getContent(nextProps,nextState);const oldHighlightedWidgets=this.props.highlightedWidgets;const newHighlightedWidgets=nextProps.highlightedWidgets;this.reuseMarkdown=!oldJipt&&!newJipt&&oldContent===newContent&&_.isEqual(this.state.translationLintErrors,nextState.translationLintErrors)&&(!this.props.linterContext.highlightLint||_.isEqual(this.props.widgets,nextProps.widgets))&&this.props.linterContext.highlightLint===nextProps.linterContext.highlightLint&&oldHighlightedWidgets===newHighlightedWidgets;}componentDidUpdate(prevProps,prevState){this.handleRender(prevProps);this.widgetIds.forEach(id=>{const container=this._widgetContainers.get(makeContainerId(id));container?.replaceWidgetProps(this.getWidgetProps(id));});if(this.props.serializedState&&!_.isEqual(this.props.serializedState,this.getSerializedState())){this.restoreSerializedState(this.props.serializedState);}if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}componentWillUnmount(){this.widgetIds=[];if(this.translationIndex!=null){getDependencies().rendererTranslationComponents.removeComponentAtIndex(this.translationIndex);}this._isMounted=false;}getWidgetProps(widgetId){const apiOptions=this.getApiOptions();const widgetProps=this.state.widgetProps[widgetId]||{};const widgetInfo=this.state.widgetInfo[widgetId];const reviewModeRubric=this.props.reviewMode&&widgetInfo?widgetInfo.options:null;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,widgetId:widgetId,alignment:widgetInfo&&widgetInfo.alignment,static:widgetInfo?.static,problemNum:this.props.problemNum,apiOptions:this.getApiOptions(),keypadElement:this.props.keypadElement,questionCompleted:this.props.questionCompleted,showSolutions:this.props.showSolutions,onFocus:_.partial(this._onWidgetFocus,widgetId),onBlur:_.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewModeRubric:reviewModeRubric,reviewMode:this.props.reviewMode,onChange:(newProps,cb,silent=false)=>{this._setWidgetProps(widgetId,newProps,cb,silent);},trackInteraction:interactionTracker.track,isLastUsedWidget:widgetId===this.state.lastUsedWidgetId}}emptyWidgets(){return emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.getUserInputMap(),this.context.locale)}getUserInput(){return this.widgetIds.map(id=>{const widget=this.getWidgetInstance(id);if(widget&&widget.getUserInput){return widget.getUserInput()}})}getUserInputMap(){const userInputMap={};this.widgetIds.forEach(id=>{const widget=this.getWidgetInstance(id);if(widget?.getUserInputMap){userInputMap[id]=widget.getUserInputMap();}else if(widget?.getUserInput){userInputMap[id]=widget.getUserInput();}});return userInputMap}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(){const scores=scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.getUserInputMap(),this.context.locale);const combinedScore=flattenScores(scores);return combinedScore}render(){const apiOptions=this.getApiOptions();if(this.reuseMarkdown){return this.lastRenderedMarkdown}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.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$1({[ClassNames.RENDERER]:true,[ClassNames.RESPONSIVE_RENDERER]:true,[ClassNames.TWO_COLUMN_RENDERER]:this._isTwoColumn});this.lastRenderedMarkdown=jsxRuntimeExports.jsx(DefinitionProvider,{children:jsxRuntimeExports.jsx("div",{className:className,children:markdownContents})});return this.lastRenderedMarkdown}constructor(props){super(props),this._widgetContainers=new Map,this.getApiOptions=()=>{return {...ApiOptions.defaults,...this.props.apiOptions}},this._getInitialWidgetState=props=>{const allWidgetInfo=getUpgradedWidgetOptions(props.widgets);return {widgetInfo:allWidgetInfo,widgetProps:this._getAllWidgetsStartProps(allWidgetInfo,props)}},this._getAllWidgetsStartProps=(allWidgetInfo,props)=>{const{apiOptions,problemNum}=props;const widgetsStartProps={};const{strings}=this.props;entries(allWidgetInfo).forEach(([key,widgetInfo])=>{widgetsStartProps[key]=getRendererPropsForWidgetInfo(widgetInfo,strings,problemNum);});apiOptions?.onWidgetStartProps?.(widgetsStartProps);return widgetsStartProps},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;const shouldHighlight=_.contains(this.props.highlightedWidgets,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,initialProps:this.getWidgetProps(id),shouldHighlight:shouldHighlight,linterContext:PerseusLinter.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.getSerializedState=widgetProps=>{return mapObject(widgetProps||this.state.widgetProps,(props,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return widget.getSerializedState()}return props})},this.restoreSerializedState=(serializedState,callback)=>{const serializedWidgetIds=_.keys(serializedState);const widgetPropIds=_.keys(this.state.widgetProps);if(serializedWidgetIds.length!==widgetPropIds.length||_.intersection(serializedWidgetIds,widgetPropIds).length!==serializedWidgetIds.length){Log.error("Refusing to restore bad serialized state:",Errors.Internal,{loggedMetadata:{serializedState:JSON.stringify(serializedState),currentProps:JSON.stringify(this.state.widgetProps)}});return}let numCallbacks=1;const fireCallback=()=>{--numCallbacks;if(callback&&numCallbacks===0){callback();}};this.setState({widgetProps:mapObject(serializedState,(props,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.restoreSerializedState){++numCallbacks;const restoreResult=widget.restoreSerializedState(props,fireCallback);return _.extend({},this.state.widgetProps[widgetId],restoreResult)}return props})},()=>{setTimeout(fireCallback,0);});},this.showRationalesForCurrentlySelectedChoices=()=>{Object.keys(this.props.widgets).forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.showRationalesForCurrentlySelectedChoices){widget.showRationalesForCurrentlySelectedChoices(this._getWidgetInfo(widgetId).options);}});},this.deselectIncorrectSelectedChoices=()=>{Object.keys(this.props.widgets).forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.deselectIncorrectSelectedChoices){widget.deselectIncorrectSelectedChoices();}});},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(!_.isArray(focusPath)){throw new PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!_.isEqual(fullPath,blurringFocusPath)){return}_.defer(()=>{if(_.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(_.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$1({"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(_.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$E.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=_.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,{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$E.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=$(ReactDOM__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'",Errors.Internal,{loggedMetadata:{focusResult:JSON.stringify(focusResult),currentProps:JSON.stringify(this.state.widgetProps)}});}else {path=[id];}this._setCurrentFocus(path);return true}},this.getDOMNodeForPath=path=>{const widgetId=_.first(path);const interWidgetPath=_.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){return ReactDOM__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(_.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=_.first(path);const interWidgetPath=_.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!_.isEqual(this._currentFocus,path)){return}const widgetId=_.first(path);const interWidgetPath=_.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={};_.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!_.isEmpty(s)){state[id]=s;}},this);return state},this._setWidgetProps=(id,newProps,cb,silent)=>{this.setState(prevState=>{const widgetProps={...prevState.widgetProps,[id]:{...prevState.widgetProps[id],...newProps}};const lastUsedWidgetId=silent?prevState.lastUsedWidgetId:id;if(!silent){this.props.onSerializedStateUpdated(this.getSerializedState(widgetProps));}return {lastUsedWidgetId,widgetProps}},()=>{setTimeout(()=>{const cbResult=cb&&cb();if(!silent){this.props.onInteractWithWidget(id);}if(cbResult!==false){this._setCurrentFocus([id]);}},0);});},this.setInputValue=(path,newValue,cb)=>{const widgetId=_.first(path);const interWidgetPath=_.rest(path);const widget=this.getWidgetInstance(widgetId);widget?.setInputValue?.(interWidgetPath,newValue,cb);},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:[],lastUsedWidgetId:null,...this._getInitialWidgetState(props)};}}Renderer.contextType=PerseusI18nContext;Renderer.defaultProps={content:"",widgets:{},images:{},highlightedWidgets:[],questionCompleted:false,showSolutions:"none",onRender:noopOnRender,onInteractWithWidget:function(){},findExternalWidgets:()=>[],alwaysUpdate:false,reviewMode:false,serializedState:null,onSerializedStateUpdated:()=>{},linterContext:PerseusLinter.linterContextDefault};const styles$E={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
|
|
1691
1692
|
|
|
1692
|
-
const{captureScratchpadTouchStart: captureScratchpadTouchStart$3}=Util;const InputWithExamples=forwardRef((
|
|
1693
|
-
${props.examples.slice(1).join(", or\n")}`.replaceAll("*","").replaceAll("$","").replaceAll("\\ \\text{pi}"," pi").replaceAll("\\ "," and "):"";const inputProps={id:id,"aria-describedby":
|
|
1693
|
+
const{captureScratchpadTouchStart: captureScratchpadTouchStart$3}=Util;const InputWithExamples=forwardRef(({shouldShowExamples=true,onFocus=()=>{},onBlur=()=>{},disabled=false,linterContext=PerseusLinter.linterContextDefault,className="",...props},ref)=>{const context=React.useContext(PerseusI18nContext);const inputRef=React.useRef(null);const[inputFocused,setInputFocused]=React.useState(false);const id=useId();const ariaId=`aria-for-${id}`;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]}
|
|
1694
|
+
${props.examples.slice(1).join(", or\n")}`.replaceAll("*","").replaceAll("$","").replaceAll("\\ \\text{pi}"," pi").replaceAll("\\ "," 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$3,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(TooltipContent,{children:jsxRuntimeExports.jsx("div",{id:id,className:"input-with-examples-tooltip",children:jsxRuntimeExports.jsx(Renderer,{content:examplesContent,linterContext:PerseusLinter.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}
|
|
1694
1695
|
`:`- ${example}`}).join("\n");const showExamplesTooltip=shouldShowExamples&&inputFocused;return jsxRuntimeExports.jsx(Tooltip,{content:renderTooltipContent(),opened:showExamplesTooltip,placement:"bottom",children:renderInput()})});
|
|
1695
1696
|
|
|
1696
|
-
const formExamples={integer:function(
|
|
1697
|
+
const formExamples={integer:function(_,strings){return strings.integerExample},proper:function(options,strings){if(options.simplify==="optional"){return strings.properExample}return strings.simplifiedProperExample},improper:function(options,strings){if(options.simplify==="optional"){return strings.improperExample}return strings.simplifiedImproperExample},mixed:function(_,strings){return strings.mixedExample},decimal:function(_,strings){return strings.decimalExample},percent:function(_,strings){return strings.percentExample},pi:function(_,strings){return strings.piExample}};class InputNumber extends React.Component{static getUserInputFromProps(props){return {currentValue:props.currentValue}}getUserInput(){return InputNumber.getUserInputFromProps(this.props)}getPromptJSON(){return getPromptJSON$s(this.props,this.getUserInput())}examples(){const{strings}=this.context;const type=this.props.answerType;const forms=inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);const examples=forms.map(form=>formExamples[form](this.props,strings));return [strings.yourAnswer].concat(examples)}render(){if(this.props.apiOptions.customKeypad){const input=jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:"input",value:this.props.currentValue,keypadElement:this.props.keypadElement,onChange:this.handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur});if(this.props.rightAlign){return jsxRuntimeExports.jsx("div",{className:"perseus-input-right-align",children:input})}return input}const inputStyles=[styles$D.default,this.props.size==="small"?styles$D.small:null,this.props.rightAlign?styles$D.rightAlign:styles$D.leftAlign];if(this.props.reviewMode&&!this.props.currentValue){inputStyles.push(styles$D.answerStateUnanswered);}return jsxRuntimeExports.jsx(InputWithExamples,{ref:"input",value:this.props.currentValue,onChange:this.handleChange,style:inputStyles,examples:this.examples(),shouldShowExamples:this.shouldShowExamples(),onFocus:this._handleFocus,onBlur:this._handleBlur,id:this.props.widgetId,disabled:this.props.apiOptions.readOnly,linterContext:this.props.linterContext})}constructor(...args){super(...args),this.shouldShowExamples=()=>{return this.props.answerType!=="number"},this.handleChange=(newValue,cb)=>{this.props.onChange({currentValue:newValue},cb);},this._handleFocus=()=>{this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{this.refs.input.focus();return true},this.focusInputPath=inputPath=>{this.refs.input.focus();},this.blurInputPath=inputPath=>{if(typeof this.refs.input?.blur==="function"){this.refs.input?.blur();}},this.getInputPaths=()=>{return [[]]},this.setInputValue=(path,newValue,cb)=>{this.props.onChange({currentValue:newValue},cb);};}}InputNumber.contextType=PerseusI18nContext;InputNumber.defaultProps={currentValue:"",size:"normal",answerType:"number",rightAlign:false,apiOptions:ApiOptions.defaults,linterContext:linterContextDefault};const styles$D=StyleSheet.create({default:{width:80,height:"auto"},small:{width:40},leftAlign:{paddingLeft:spacing.xxxSmall_4,paddingRight:0},rightAlign:{textAlign:"right",paddingLeft:0,paddingRight:spacing.xxxSmall_4},answerStateUnanswered:{backgroundColor:"#eee",border:"solid 1px #999"}});function transform$3(widgetOptions){const{simplify,size,answerType,rightAlign}=widgetOptions;return {simplify,size,answerType,rightAlign}}function getOneCorrectAnswerFromRubric(rubric){if(rubric.value==null){return}let answerString=String(rubric.value);if(rubric.inexact&&rubric.maxError){answerString+=" ± "+rubric.maxError;}return answerString}var InputNumber$1 = {name:"input-number",displayName:"Input number (deprecated - use numeric input instead)",hidden:true,widget:InputNumber,isLintable:true,transform: transform$3,getOneCorrectAnswerFromRubric};
|
|
1697
1698
|
|
|
1698
1699
|
const getPromptJSON$r=(renderProps,userInput)=>{return {type:"numeric-input",label:renderProps.labelText,userInput:{value:userInput.currentValue}}};
|
|
1699
1700
|
|
|
@@ -1781,7 +1782,7 @@ let Radio$2 = class Radio extends React.Component{static getUserInputFromProps(p
|
|
|
1781
1782
|
|
|
1782
1783
|
let Radio$1 = class Radio extends Radio$3{focus(choiceIndex){if(this.radioRef.current){return this.radioRef.current.focus(choiceIndex)}return false}render(){const RadioProper=this.ffIsOn?Radio$2:Radio$3;return jsxRuntimeExports.jsx(RadioProper,{ref:this.radioRef,...this.props})}constructor(props){super(props),this.ffIsOn=false,this.radioRef=React.createRef();this.ffIsOn=props.apiOptions.flags?.["new-radio-widget"]??false;}};
|
|
1783
1784
|
|
|
1784
|
-
const _choiceTransform=(widgetOptions,strings,problemNum)=>{const _maybeRandomize=function(array){const randomSeed=problemNum===undefined?random:problemNum;return widgetOptions.randomize?shuffle(array,randomSeed??0):array};const _addNoneOfAbove=function(choices){let noneOfTheAbove=null;const newChoices=choices.filter((choice,index)=>{if(choice.isNoneOfTheAbove){noneOfTheAbove=choice;return false}return true});if(noneOfTheAbove){newChoices.push(noneOfTheAbove);}return newChoices};const enforceOrdering=choices=>{const ReversedChoices=[[strings.false,strings.true],[strings.no,strings.yes]];const content=choices.map(c=>c.content);if(ReversedChoices.some(reversed=>_.isEqual(content,reversed))){return [choices[1],choices[0]]}return choices};const choices=widgetOptions.choices.map((choice,i)=>{return {...choice,originalIndex:i,correct:Boolean(choice.correct)}});return _addNoneOfAbove(enforceOrdering(_maybeRandomize(choices)))};const transform$
|
|
1785
|
+
const _choiceTransform=(widgetOptions,strings,problemNum)=>{const _maybeRandomize=function(array){const randomSeed=problemNum===undefined?random:problemNum;return widgetOptions.randomize?shuffle(array,randomSeed??0):array};const _addNoneOfAbove=function(choices){let noneOfTheAbove=null;const newChoices=choices.filter((choice,index)=>{if(choice.isNoneOfTheAbove){noneOfTheAbove=choice;return false}return true});if(noneOfTheAbove){newChoices.push(noneOfTheAbove);}return newChoices};const enforceOrdering=choices=>{const ReversedChoices=[[strings.false,strings.true],[strings.no,strings.yes]];const content=choices.map(c=>c.content);if(ReversedChoices.some(reversed=>_.isEqual(content,reversed))){return [choices[1],choices[0]]}return choices};const choices=widgetOptions.choices.map((choice,i)=>{return {...choice,originalIndex:i,correct:Boolean(choice.correct)}});return _addNoneOfAbove(enforceOrdering(_maybeRandomize(choices)))};const transform$2=(widgetOptions,strings,problemNum)=>{const choices=_choiceTransform(widgetOptions,strings,problemNum);const{hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,numCorrect}=widgetOptions;return {numCorrect:numCorrect,hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,choices,selectedChoices:_.pluck(choices,"correct")}};var Radio = {name:"radio",displayName:"Radio / Multiple choice",accessible:true,widget:Radio$1,transform:transform$2,staticTransform:transform$2,version:radioLogic.version,propUpgrades:radioLogic.widgetOptionsUpgrades,isLintable:true};
|
|
1785
1786
|
|
|
1786
1787
|
var basicWidgets = [Radio,InputNumber$1,NumericInput$1,Expression$1];
|
|
1787
1788
|
|
|
@@ -1809,7 +1810,7 @@ class DeprecatedStandin extends React__default.Component{render(){return jsxRunt
|
|
|
1809
1810
|
|
|
1810
1811
|
const getPromptJSON$k=(renderProps,userInput)=>{return {type:"dropdown",options:{items:renderProps.choices},userInput:{selectedIndex:userInput.value-1}}};
|
|
1811
1812
|
|
|
1812
|
-
class Dropdown extends React.Component{getUserInput(){return {value:this.props.selected}}getPromptJSON(){return getPromptJSON$k(this.props,this.getUserInput())}render(){const children=[jsxRuntimeExports.jsx(OptionItem,{value:"0",disabled:true,label:jsxRuntimeExports.jsx(Renderer,{content:this.props.placeholder,strings:this.context.strings}),labelAsText:this.props.placeholder},"placeholder"),...this.props.choices.map((choice,i)=>jsxRuntimeExports.jsx(OptionItem,{value:String(i+1),label:jsxRuntimeExports.jsx(Renderer,{content:choice,strings:this.context.strings}),labelAsText:choice},String(i+1)))];return jsxRuntimeExports.jsx(Id,{children:dropdownId=>jsxRuntimeExports.jsxs(View,{onClick:e=>{e.stopPropagation();},onTouchStart:e=>{e.stopPropagation();},children:[this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelLarge,{tag:"label",htmlFor:dropdownId,children:this.props.visibleLabel}),jsxRuntimeExports.jsx(SingleSelect,{id:dropdownId,placeholder:"",className:"perseus-dropdown",onChange:value=>this._handleChange(parseInt(value)),selectedValue:String(this.props.selected),disabled:this.props.apiOptions.readOnly,"aria-label":this.props.ariaLabel||this.props.visibleLabel||this.context.strings.selectAnAnswer,showOpenerLabelAsText:false,children:children})]})})}constructor(...args){super(...args),this.focus=()=>{ReactDOM__default.findDOMNode(this).focus();return true},this._handleChangeEvent=e=>{this._handleChange(parseInt(e.target.value));},this._handleChange=selected=>{this.props.trackInteraction();this.props.onChange({selected:selected});};}}Dropdown.contextType=PerseusI18nContext;Dropdown.defaultProps={choices:[],selected:0,placeholder:"",apiOptions:ApiOptions.defaults};function transform(widgetOptions){return {placeholder:widgetOptions.placeholder,visibleLabel:widgetOptions.visibleLabel,ariaLabel:widgetOptions.ariaLabel,choices:widgetOptions.choices.map(choice=>choice.content)}}var Dropdown$1 = {name:"dropdown",displayName:"Drop down",accessible:true,widget:Dropdown,transform};
|
|
1813
|
+
class Dropdown extends React.Component{getUserInput(){return {value:this.props.selected}}getPromptJSON(){return getPromptJSON$k(this.props,this.getUserInput())}render(){const children=[jsxRuntimeExports.jsx(OptionItem,{value:"0",disabled:true,label:jsxRuntimeExports.jsx(Renderer,{content:this.props.placeholder,strings:this.context.strings}),labelAsText:this.props.placeholder},"placeholder"),...this.props.choices.map((choice,i)=>jsxRuntimeExports.jsx(OptionItem,{value:String(i+1),label:jsxRuntimeExports.jsx(Renderer,{content:choice,strings:this.context.strings}),labelAsText:choice},String(i+1)))];return jsxRuntimeExports.jsx(Id,{children:dropdownId=>jsxRuntimeExports.jsxs(View,{onClick:e=>{e.stopPropagation();},onTouchStart:e=>{e.stopPropagation();},children:[this.props.visibleLabel&&jsxRuntimeExports.jsx(LabelLarge,{tag:"label",htmlFor:dropdownId,children:this.props.visibleLabel}),jsxRuntimeExports.jsx(SingleSelect,{id:dropdownId,placeholder:"",className:"perseus-dropdown",onChange:value=>this._handleChange(parseInt(value)),selectedValue:String(this.props.selected),disabled:this.props.apiOptions.readOnly,"aria-label":this.props.ariaLabel||this.props.visibleLabel||this.context.strings.selectAnAnswer,showOpenerLabelAsText:false,children:children})]})})}constructor(...args){super(...args),this.focus=()=>{ReactDOM__default.findDOMNode(this).focus();return true},this._handleChangeEvent=e=>{this._handleChange(parseInt(e.target.value));},this._handleChange=selected=>{this.props.trackInteraction();this.props.onChange({selected:selected});};}}Dropdown.contextType=PerseusI18nContext;Dropdown.defaultProps={choices:[],selected:0,placeholder:"",apiOptions:ApiOptions.defaults};function transform$1(widgetOptions){return {placeholder:widgetOptions.placeholder,visibleLabel:widgetOptions.visibleLabel,ariaLabel:widgetOptions.ariaLabel,choices:widgetOptions.choices.map(choice=>choice.content)}}var Dropdown$1 = {name:"dropdown",displayName:"Drop down",accessible:true,widget:Dropdown,transform: transform$1};
|
|
1813
1814
|
|
|
1814
1815
|
const getPromptJSON$j=renderProps=>{return {type:"explanation",showPrompt:renderProps.showPrompt,explanation:renderProps.explanation}};
|
|
1815
1816
|
|
|
@@ -1825,13 +1826,13 @@ const getPromptJSON$h=(renderProps,activeGroupJSON)=>{return {type:"graded-group
|
|
|
1825
1826
|
|
|
1826
1827
|
class Indicators extends React.Component{render(){return jsxRuntimeExports.jsx("ul",{className:classNames$1(css(styles$h.indicatorContainer),"indicatorContainer"),children:this.props.gradedGroups.map(({title},i)=>jsxRuntimeExports.jsx("li",{className:css(styles$h.indicator),children:jsxRuntimeExports.jsx(Clickable,{role:"button","aria-label":this.context.strings.skipToTitle({title}),style:styles$h.indicatorButton,onClick:()=>this.props.onChangeCurrentGroup(i),onKeyDown:e=>this.handleKeyDown(e,i),children:({hovered,focused,pressed})=>jsxRuntimeExports.jsx(View,{style:[styles$h.indicatorDot,(hovered||focused||pressed)&&styles$h.indicatorDotFocused],children:i===this.props.currentGroup&&jsxRuntimeExports.jsx(View,{style:styles$h.indicatorDotActive,children:jsxRuntimeExports.jsx("span",{className:css(a11y.srOnly),children:this.context.strings.current})})})})},title))})}constructor(...args){super(...args),this.handleKeyDown=(e,i)=>{if(e.key==="Enter"||e.key===" "){this.props.onChangeCurrentGroup(i);}};}}Indicators.contextType=PerseusI18nContext;class GradedGroupSet extends React.Component{shouldComponentUpdate(nextProps,nextState){return nextProps!==this.props||nextState!==this.state}getPromptJSON(){const activeGroupPromptJSON=this._childGroup.getPromptJSON();return getPromptJSON$h(this.props,activeGroupPromptJSON)}render(){const{JIPT}=getDependencies();if(JIPT.useJIPT&&this.props.gradedGroups.length>1){return jsxRuntimeExports.jsx("div",{className:css(styles$h.container),children:this.props.gradedGroups.map((gradedGroup,i)=>{return jsxRuntimeExports.jsx(GradedGroup,{...this.props,...gradedGroup,inGradedGroupSet:false,linterContext:this.props.linterContext},i)})})}const currentGroup=this.props.gradedGroups[this.state.currentGroup];if(!currentGroup){return jsxRuntimeExports.jsx("span",{children:"No current group..."})}const numGroups=this.props.gradedGroups.length;const handleNextQuestion=this.state.currentGroup<numGroups-1?this.handleNextQuestion:null;return jsxRuntimeExports.jsxs("div",{className:css(styles$h.container),children:[jsxRuntimeExports.jsxs("div",{className:css(styles$h.top),children:[jsxRuntimeExports.jsx("div",{className:css(styles$h.title),children:currentGroup.title}),jsxRuntimeExports.jsx("div",{className:css(styles$h.spacer)}),jsxRuntimeExports.jsx(Indicators,{currentGroup:this.state.currentGroup,gradedGroups:this.props.gradedGroups,onChangeCurrentGroup:currentGroup=>this.setState({currentGroup})})]}),jsxRuntimeExports.jsx(GradedGroup,{ref:comp=>this._childGroup=comp,...this.props,...currentGroup,inGradedGroupSet:true,title:null,onNextQuestion:handleNextQuestion,linterContext:this.props.linterContext},this.state.currentGroup)]})}constructor(...args){super(...args),this.state={currentGroup:0},this.change=(...args)=>{return change.apply(this,args)},this.getInputPaths=()=>{return this._childGroup.getInputPaths()},this.setInputValue=(path,newValue,cb)=>{return this._childGroup.setInputValue(path,newValue,cb)},this.focus=()=>{return this._childGroup.focus()},this.focusInputPath=path=>{this._childGroup.focusInputPath(path);},this.blurInputPath=path=>{this._childGroup.blurInputPath(path);},this.handleNextQuestion=()=>{const{currentGroup}=this.state;const numGroups=this.props.gradedGroups.length;if(currentGroup<numGroups-1){this.setState({currentGroup:currentGroup+1});}};}}GradedGroupSet.defaultProps={gradedGroups:[],linterContext:linterContextDefault};const traverseChildWidgets$1=function(props,traverseRenderer){return {groups:props.gradedGroups.map(traverseRenderer)}};var GradedGroupSet$1 = {name:"graded-group-set",displayName:"Graded group set (articles only)",widget:GradedGroupSet,traverseChildWidgets:traverseChildWidgets$1,hidden:false,tracking:"all",isLintable:true};const styles$h=StyleSheet.create({top:{display:"flex",flexDirection:"row"},spacer:{flex:1},title:{fontSize:12,color:color.offBlack64,textTransform:"uppercase",marginBottom:11,letterSpacing:.8},indicatorContainer:{display:"flex",flexDirection:"row",listStyle:"none",margin:"unset",paddingInlineStart:"unset",flexWrap:"wrap"},indicator:{width:24,height:24},indicatorButton:{width:"100%",height:"100%",display:"flex",flexWrap:"wrap",placeContent:"center",cursor:"pointer",":focus":{outline:"none"}},indicatorDot:{boxSizing:"content-box",width:10,height:10,borderRadius:"100%",borderWidth:2,borderColor:color.blue,borderStyle:"solid"},indicatorDotFocused:{borderWidth:5,borderStyle:"double"},indicatorDotActive:{backgroundColor:color.blue,width:"100%",height:"100%"},container:{borderTop:`1px solid ${gray76}`,borderBottom:`1px solid ${gray76}`,backgroundColor:tableBackgroundAccent,marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin,paddingBottom:phoneMargin,paddingLeft:phoneMargin,paddingRight:phoneMargin,paddingTop:10,width:"auto"}});
|
|
1827
1828
|
|
|
1828
|
-
class ButtonGroup extends React.Component{componentWillUnmount(){this.container=null;}focus(){if(this.container){this.container.focus();return true}}toggleSelect(newValue){const value=this.props.value;if(this.props.allowEmpty){this.props.onChange(value!==newValue?newValue:null);}else {this.props.onChange(newValue);}}render(){const value=this.props.value;const buttons=this.props.buttons.map((button,i)=>{return jsxRuntimeExports.jsx("button",{title:button.title,type:"button",
|
|
1829
|
+
class ButtonGroup extends React.Component{componentWillUnmount(){this.container=null;}focus(){if(this.container){this.container.focus();return true}}toggleSelect(newValue){const value=this.props.value;if(this.props.allowEmpty){this.props.onChange(value!==newValue?newValue:null);}else {this.props.onChange(newValue);}}render(){const value=this.props.value;const buttons=this.props.buttons.map((button,i)=>{return jsxRuntimeExports.jsx("button",{title:button.title,type:"button",ref:"button"+i,className:css(styles$g.buttonStyle,button.value===value&&styles$g.selectedStyle,button.value===value&&this.props.selectedButtonStyle),onClick:()=>this.toggleSelect(button.value),children:button.content||""+button.value},""+i)});const outerStyle={display:"inline-block"};return jsxRuntimeExports.jsx("div",{style:outerStyle,ref:node=>this.container=node,children:buttons})}}ButtonGroup.defaultProps={value:null,allowEmpty:true};const styles$g=StyleSheet.create({buttonStyle:{backgroundColor:"white",border:"1px solid #ccc",borderLeft:"0",cursor:"pointer",margin:"0",padding:"5px 10px",position:"relative",":first-child":{borderLeft:"1px solid #ccc",borderTopLeftRadius:"3px",borderBottomLeftRadius:"3px"},":last-child":{borderRight:"1px solid #ccc",borderTopRightRadius:"3px",borderBottomRightRadius:"3px"},":hover":{backgroundColor:"#ccc"},":focus":{zIndex:2}},selectedStyle:{backgroundColor:"#ddd"}});
|
|
1829
1830
|
|
|
1830
1831
|
const getPromptJSON$g=(renderProps,userInput)=>{const{type,coords}=userInput;const input={type,coords};if(userInput.type==="logarithm"||userInput.type==="exponential"){input["asymptote"]=userInput.asymptote;}return {type:"grapher",options:{availableTypes:renderProps.availableTypes,range:renderProps.graph.range,labels:renderProps.graph.labels,tickStep:renderProps.graph.step,gridStep:renderProps.graph.gridStep,snapStep:renderProps.graph.snapStep,backgroundImageUrl:renderProps.graph.backgroundImage.url},userInput:input}};
|
|
1831
1832
|
|
|
1832
1833
|
const movableTypeToComponent={PLOT:Graphie.Plot,PARABOLA:Graphie.Parabola,SINUSOID:Graphie.Sinusoid};const DEFAULT_BACKGROUND_IMAGE={url:null};const getEquationString=props=>{const plot=props.plot;if(plot.type&&plot.coords){const handler=GrapherUtil$1.functionForType(plot.type);const result=handler.getEquationString(plot.coords,plot.asymptote);return result||""}return ""};const pointsFromNormalized=(coordsList,range,step,snapStep)=>{const numSteps=function(range,step){return Math.floor((range[1]-range[0])/step)};return coordsList.map(coords=>{const unsnappedPoint=coords.map((coord,i)=>{const currRange=range[i];const currStep=step[i];const nSteps=numSteps(currRange,currStep);const tick=Math.round(coord*nSteps);return currRange[0]+currStep*tick});return point.roundTo(unsnappedPoint,snapStep)})};const maybePointsFromNormalized=(coordsList,range,step,snapStep)=>{if(coordsList){return pointsFromNormalized(coordsList,range,step,snapStep)}return coordsList};const defaultPlotProps=(type,graph)=>{const model=GrapherUtil$1.functionForType(type);const defaultAsymptote="defaultAsymptote"in model?model.defaultAsymptote:null;const gridStep=[1,1];const snapStep=Util.snapStepFromGridStep(gridStep);return {type,asymptote:maybePointsFromNormalized(defaultAsymptote,graph.range,graph.step,snapStep),coords:null}};const chooseType=_.first;const getGridAndSnapSteps=(options,boxSize)=>{const gridStep=options.gridStep||Util.getGridStep(options.range,options.step,boxSize);const snapStep=options.snapStep||Util.snapStepFromGridStep(gridStep);return {gridStep:gridStep,snapStep:snapStep}};const defaultGraph={labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],backgroundImage:DEFAULT_BACKGROUND_IMAGE,markings:"graph",rulerLabel:"",rulerTicks:10,valid:true,showTooltips:false};const defaultPlot=defaultPlotProps("linear",defaultGraph);const DEFAULT_GRAPHER_PROPS={graph:defaultGraph,plot:defaultPlot,availableTypes:[defaultPlot.type]};const typeToButton=type=>{const capitalized=type.charAt(0).toUpperCase()+type.substring(1);const staticUrl=getDependencies().staticUrl;return {value:type,title:capitalized,content:jsxRuntimeExports.jsx("img",{src:staticUrl(GrapherUtil$1.functionForType(type).url),alt:capitalized})}};
|
|
1833
1834
|
|
|
1834
|
-
const MovablePoint$3=Graphie.MovablePoint;const MovableLine$2=Graphie.MovableLine;function isFlipped(newCoord,oldCoord,line){const CCW=(a,b,c)=>{return (b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])};return CCW(line[0],line[1],oldCoord)>0!==CCW(line[0],line[1],newCoord)>0}const typeSelectorStyle={padding:"5px 5px"};class FunctionGrapher extends React.Component{render(){const pointForCoord=(coord,i)=>{return jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:this.props.static,constraints:[Interactive2.MovablePoint.constraints.bound(),Interactive2.MovablePoint.constraints.snap(),coord=>{const isFunction=_.all(this._coords(),(otherCoord,j)=>{return i===j||!otherCoord||!number.equal(coord[0],otherCoord[0])});if(!isFunction){return false}if(this.props.model&&this.props.model.extraCoordConstraint){const extraConstraint=this.props.model.extraCoordConstraint;const proposedCoords=_.clone(this._coords());const oldCoord=_.clone(proposedCoords[i]);proposedCoords[i]=coord;return extraConstraint(coord,oldCoord,proposedCoords,this._asymptote(),this.props.graph)}return isFunction}],onMove:(newCoord,oldCoord)=>{let coords;const asymptote=this._asymptote();if(asymptote&&this.props.model.allowReflectOverAsymptote&&isFlipped(newCoord,oldCoord,asymptote)){coords=_.map(this._coords(),coord=>{return point.reflectOverLine(coord,asymptote)});}else {coords=_.clone(this._coords());}coords[i]=newCoord;this.props.onChange({coords:coords});},showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},i)};const points=_.map(this._coords(),pointForCoord);const box=this.props.graph.box;const imageDescription=this.props.graph.backgroundImage;let image=null;if(imageDescription.url){const scale=box[0]/interactiveSizes$1.defaultBoxSize;image=jsxRuntimeExports.jsx(SvgImage,{src:imageDescription.url,width:imageDescription.width,height:imageDescription.height,scale:scale});}return jsxRuntimeExports.jsx("div",{className:"perseus-widget "+"perseus-widget-grapher",style:{width:box[0],height:box[1],boxSizing:"initial"},children:jsxRuntimeExports.jsxs("div",{className:"graphie-container blank-background",style:{width:box[0],height:box[1]},children:[image,jsxRuntimeExports.jsxs(Graphie,{...this.props.graph,setDrawingAreaAvailable:this.props.setDrawingAreaAvailable,children:[this.props.model&&this.renderPlot(),this.props.model&&this.renderAsymptote(),this.props.model&&points]})]})})}constructor(...args){super(...args),this._coords=()=>{const props=this.props;const graph=props.graph;const defaultModelCoords=props.model&&maybePointsFromNormalized(props.model.defaultCoords,graph.range,graph.step,graph.snapStep);return props.coords||defaultModelCoords||null},this._asymptote=()=>{return this.props.asymptote},this.change=(...args)=>{return change.apply(this,args)},this.renderPlot=()=>{const model=this.props.model;const xRange=this.props.graph.range[0];const style={stroke:this.props.isMobile?KhanColors.BLUE_C:KhanColors.DYNAMIC,...this.props.isMobile?{"stroke-width":3}:{}};const coeffs=model.getCoefficients(this._coords(),this._asymptote());if(!coeffs){return}const functionProps=model.getPropsForCoeffs(coeffs,xRange);const Movable=movableTypeToComponent[model.movable];return createElement(Movable,{...functionProps,key:this.props.model.url,range:xRange,style:style})},this.renderAsymptote=()=>{const model=this.props.model;const graph=this.props.graph;const asymptote=this._asymptote();const showAsymptote=asymptote?.length>0;const dashed={strokeDasharray:"- "};return showAsymptote&&jsxRuntimeExports.jsx(MovableLine$2,{onMove:(newCoord,oldCoord)=>{const delta=vector$3.subtract(newCoord,oldCoord);const newAsymptote=_.map(this._asymptote(),coord=>vector$3.add(coord,delta));this.props.onChange({asymptote:newAsymptote});},constraints:[Interactive2.MovableLine.constraints.bound(),Interactive2.MovableLine.constraints.snap(),(newCoord,oldCoord)=>{const delta=vector$3.subtract(newCoord,oldCoord);const proposedAsymptote=_.map(this._asymptote(),coord=>vector$3.add(coord,delta));if(model.extraAsymptoteConstraint){return model.extraAsymptoteConstraint(newCoord,oldCoord,this._coords(),proposedAsymptote,graph)}return true}],normalStyle:dashed,highlightStyle:dashed,children:_.map(asymptote,(coord,i)=>jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:true,draw:null,extendLine:true,showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},`asymptoteCoord-${i}`))})};}}FunctionGrapher.defaultProps={graph:{range:[[-10,10],[-10,10]],step:[1,1]},coords:null,asymptote:null,isMobile:false};class Grapher extends React.Component{static getUserInputFromProps(props){return props.plot}_getGridConfig(options){return options.step.map((step,i)=>{return Util.gridDimensionConfig(step,options.range[i],options.box[i],options.gridStep[i])})}_calculateMobileTickStep(gridStep,step,ranges){const tickStep=Util.constrainedTickStepsFromTickSteps(step,ranges);tickStep[0]=tickStep[0]/gridStep[0];tickStep[1]=tickStep[1]/gridStep[1];return tickStep}getUserInput(){return Grapher.getUserInputFromProps(this.props)}getPromptJSON(){return getPromptJSON$g(this.props,this.getUserInput())}render(){const type=this.props.plot.type;const coords=this.props.plot.coords;const asymptote=this.props.plot.asymptote;const typeSelector=jsxRuntimeExports.jsx("div",{style:typeSelectorStyle,children:jsxRuntimeExports.jsx(ButtonGroup,{value:type,allowEmpty:true,buttons:_.map(this.props.availableTypes,typeToButton),onChange:this.handleActiveTypeChange})});const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const options={...this.props.graph,...getGridAndSnapSteps(this.props.graph,box[0]),gridConfig:this._getGridConfig({...this.props.graph,box:box,...getGridAndSnapSteps(this.props.graph,box[0])})};const grapherProps={graph:{box:box,range:options.range,step:options.step,snapStep:options.snapStep,backgroundImage:options.backgroundImage,options:options,setup:this._setupGraphie},onChange:this.handlePlotChanges,model:type&&GrapherUtil$1.functionForType(type),coords:coords,asymptote:asymptote,static:this.props.static,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable,isMobile:this.props.apiOptions.isMobile,showTooltips:this.props.graph.showTooltips,showHairlines:this.showHairlines,hideHairlines:this.hideHairlines};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(FunctionGrapher,{...grapherProps}),this.props.availableTypes.length>1&&typeSelector]})}constructor(...args){super(...args),this.handlePlotChanges=newPlot=>{const plot=_.extend({},this.props.plot,newPlot);this.props.onChange({plot:plot});this.props.trackInteraction();},this.handleActiveTypeChange=newType=>{const graph=this.props.graph;const plot=_.extend({},this.props.plot,defaultPlotProps(newType,graph));this.props.onChange({plot:plot});},this._setupGraphie=(graphie,options)=>{const isMobile=this.props.apiOptions.isMobile;if(options.markings==="graph"){graphie.graphInit({range:options.range,scale:_.pluck(options.gridConfig,"scale"),axisArrows:"<->",labelFormat:function(s){return "\\small{"+s+"}"},gridStep:options.gridStep,snapStep:options.snapStep,tickStep:isMobile?this._calculateMobileTickStep(options.gridStep,options.step,options.range):_.pluck(options.gridConfig,"tickStep"),labelStep:1,unityLabels:_.pluck(options.gridConfig,"unityLabel"),isMobile:isMobile});graphie.label([0,options.range[1][1]],options.labels[1],isMobile?"below right":"above");graphie.label([options.range[0][1],0],options.labels[0],isMobile?"above left":"right");}else if(options.markings==="grid"){graphie.graphInit({range:options.range,scale:_.pluck(options.gridConfig,"scale"),gridStep:options.gridStep,axes:false,ticks:false,labels:false,isMobile:isMobile});}else if(options.markings==="none"){graphie.init({range:options.range,scale:_.pluck(options.gridConfig,"scale")});}if(this.props.apiOptions.isMobile){const hairlineStyle={normalStyle:{strokeWidth:1}};this.horizHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.vertHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.vertHairline.attr({stroke:KhanColors.INTERACTIVE});this.vertHairline.hide();}},this.showHairlines=point=>{if(this.props.apiOptions.isMobile&&this.props.markings!=="none"){this.horizHairline.moveTo([this.props.graph.range[0][0],point[1]],[this.props.graph.range[0][1],point[1]]);this.horizHairline.show();this.vertHairline.moveTo([point[0],this.props.graph.range[1][0]],[point[0],this.props.graph.range[1][1]]);this.vertHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();this.vertHairline.hide();}};}}Grapher.defaultProps=DEFAULT_GRAPHER_PROPS;const propTransform$
|
|
1835
|
+
const MovablePoint$3=Graphie.MovablePoint;const MovableLine$2=Graphie.MovableLine;function isFlipped(newCoord,oldCoord,line){const CCW=(a,b,c)=>{return (b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])};return CCW(line[0],line[1],oldCoord)>0!==CCW(line[0],line[1],newCoord)>0}const typeSelectorStyle={padding:"5px 5px"};class FunctionGrapher extends React.Component{render(){const pointForCoord=(coord,i)=>{return jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:this.props.static,constraints:[Interactive2.MovablePoint.constraints.bound(),Interactive2.MovablePoint.constraints.snap(),coord=>{const isFunction=_.all(this._coords(),(otherCoord,j)=>{return i===j||!otherCoord||!number.equal(coord[0],otherCoord[0])});if(!isFunction){return false}if(this.props.model&&this.props.model.extraCoordConstraint){const extraConstraint=this.props.model.extraCoordConstraint;const proposedCoords=_.clone(this._coords());const oldCoord=_.clone(proposedCoords[i]);proposedCoords[i]=coord;return extraConstraint(coord,oldCoord,proposedCoords,this._asymptote(),this.props.graph)}return isFunction}],onMove:(newCoord,oldCoord)=>{let coords;const asymptote=this._asymptote();if(asymptote&&this.props.model.allowReflectOverAsymptote&&isFlipped(newCoord,oldCoord,asymptote)){coords=_.map(this._coords(),coord=>{return point.reflectOverLine(coord,asymptote)});}else {coords=_.clone(this._coords());}coords[i]=newCoord;this.props.onChange({coords:coords});},showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},i)};const points=_.map(this._coords(),pointForCoord);const box=this.props.graph.box;const imageDescription=this.props.graph.backgroundImage;let image=null;if(imageDescription.url){const scale=box[0]/interactiveSizes$1.defaultBoxSize;image=jsxRuntimeExports.jsx(SvgImage,{src:imageDescription.url,width:imageDescription.width,height:imageDescription.height,scale:scale});}return jsxRuntimeExports.jsx("div",{className:"perseus-widget "+"perseus-widget-grapher",style:{width:box[0],height:box[1],boxSizing:"initial"},children:jsxRuntimeExports.jsxs("div",{className:"graphie-container blank-background",style:{width:box[0],height:box[1]},children:[image,jsxRuntimeExports.jsxs(Graphie,{...this.props.graph,setDrawingAreaAvailable:this.props.setDrawingAreaAvailable,children:[this.props.model&&this.renderPlot(),this.props.model&&this.renderAsymptote(),this.props.model&&points]})]})})}constructor(...args){super(...args),this._coords=()=>{const props=this.props;const graph=props.graph;const defaultModelCoords=props.model&&maybePointsFromNormalized(props.model.defaultCoords,graph.range,graph.step,graph.snapStep);return props.coords||defaultModelCoords||null},this._asymptote=()=>{return this.props.asymptote},this.change=(...args)=>{return change.apply(this,args)},this.renderPlot=()=>{const model=this.props.model;const xRange=this.props.graph.range[0];const style={stroke:this.props.isMobile?KhanColors.BLUE_C:KhanColors.DYNAMIC,...this.props.isMobile?{"stroke-width":3}:{}};const coeffs=model.getCoefficients(this._coords(),this._asymptote());if(!coeffs){return}const functionProps=model.getPropsForCoeffs(coeffs,xRange);const Movable=movableTypeToComponent[model.movable];return createElement(Movable,{...functionProps,key:this.props.model.url,range:xRange,style:style})},this.renderAsymptote=()=>{const model=this.props.model;const graph=this.props.graph;const asymptote=this._asymptote();const showAsymptote=asymptote?.length>0;const dashed={strokeDasharray:"- "};return showAsymptote&&jsxRuntimeExports.jsx(MovableLine$2,{onMove:(newCoord,oldCoord)=>{const delta=vector$3.subtract(newCoord,oldCoord);const newAsymptote=_.map(this._asymptote(),coord=>vector$3.add(coord,delta));this.props.onChange({asymptote:newAsymptote});},constraints:[Interactive2.MovableLine.constraints.bound(),Interactive2.MovableLine.constraints.snap(),(newCoord,oldCoord)=>{const delta=vector$3.subtract(newCoord,oldCoord);const proposedAsymptote=_.map(this._asymptote(),coord=>vector$3.add(coord,delta));if(model.extraAsymptoteConstraint){return model.extraAsymptoteConstraint(newCoord,oldCoord,this._coords(),proposedAsymptote,graph)}return true}],normalStyle:dashed,highlightStyle:dashed,children:_.map(asymptote,(coord,i)=>jsxRuntimeExports.jsx(MovablePoint$3,{coord:coord,static:true,draw:null,extendLine:true,showHairlines:this.props.showHairlines,hideHairlines:this.props.hideHairlines,showTooltips:this.props.showTooltips,isMobile:this.props.isMobile},`asymptoteCoord-${i}`))})};}}FunctionGrapher.defaultProps={graph:{range:[[-10,10],[-10,10]],step:[1,1]},coords:null,asymptote:null,isMobile:false};class Grapher extends React.Component{static getUserInputFromProps(props){return props.plot}_getGridConfig(options){return options.step.map((step,i)=>{return Util.gridDimensionConfig(step,options.range[i],options.box[i],options.gridStep[i])})}_calculateMobileTickStep(gridStep,step,ranges){const tickStep=Util.constrainedTickStepsFromTickSteps(step,ranges);tickStep[0]=tickStep[0]/gridStep[0];tickStep[1]=tickStep[1]/gridStep[1];return tickStep}getUserInput(){return Grapher.getUserInputFromProps(this.props)}getPromptJSON(){return getPromptJSON$g(this.props,this.getUserInput())}render(){const type=this.props.plot.type;const coords=this.props.plot.coords;const asymptote=this.props.plot.asymptote;const typeSelector=jsxRuntimeExports.jsx("div",{style:typeSelectorStyle,children:jsxRuntimeExports.jsx(ButtonGroup,{value:type,allowEmpty:true,buttons:_.map(this.props.availableTypes,typeToButton),onChange:this.handleActiveTypeChange})});const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const options={...this.props.graph,...getGridAndSnapSteps(this.props.graph,box[0]),gridConfig:this._getGridConfig({...this.props.graph,box:box,...getGridAndSnapSteps(this.props.graph,box[0])})};const grapherProps={graph:{box:box,range:options.range,step:options.step,snapStep:options.snapStep,backgroundImage:options.backgroundImage,options:options,setup:this._setupGraphie},onChange:this.handlePlotChanges,model:type&&GrapherUtil$1.functionForType(type),coords:coords,asymptote:asymptote,static:this.props.static,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable,isMobile:this.props.apiOptions.isMobile,showTooltips:this.props.graph.showTooltips,showHairlines:this.showHairlines,hideHairlines:this.hideHairlines};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(FunctionGrapher,{...grapherProps}),this.props.availableTypes.length>1&&typeSelector]})}constructor(...args){super(...args),this.handlePlotChanges=newPlot=>{const plot=_.extend({},this.props.plot,newPlot);this.props.onChange({plot:plot});this.props.trackInteraction();},this.handleActiveTypeChange=newType=>{const graph=this.props.graph;const plot=_.extend({},this.props.plot,defaultPlotProps(newType,graph));this.props.onChange({plot:plot});},this._setupGraphie=(graphie,options)=>{const isMobile=this.props.apiOptions.isMobile;if(options.markings==="graph"){graphie.graphInit({range:options.range,scale:_.pluck(options.gridConfig,"scale"),axisArrows:"<->",labelFormat:function(s){return "\\small{"+s+"}"},gridStep:options.gridStep,snapStep:options.snapStep,tickStep:isMobile?this._calculateMobileTickStep(options.gridStep,options.step,options.range):_.pluck(options.gridConfig,"tickStep"),labelStep:1,unityLabels:_.pluck(options.gridConfig,"unityLabel"),isMobile:isMobile});graphie.label([0,options.range[1][1]],options.labels[1],isMobile?"below right":"above");graphie.label([options.range[0][1],0],options.labels[0],isMobile?"above left":"right");}else if(options.markings==="grid"){graphie.graphInit({range:options.range,scale:_.pluck(options.gridConfig,"scale"),gridStep:options.gridStep,axes:false,ticks:false,labels:false,isMobile:isMobile});}else if(options.markings==="none"){graphie.init({range:options.range,scale:_.pluck(options.gridConfig,"scale")});}if(this.props.apiOptions.isMobile){const hairlineStyle={normalStyle:{strokeWidth:1}};this.horizHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.vertHairline=new WrappedLine(graphie,[0,0],[0,0],hairlineStyle);this.vertHairline.attr({stroke:KhanColors.INTERACTIVE});this.vertHairline.hide();}},this.showHairlines=point=>{if(this.props.apiOptions.isMobile&&this.props.markings!=="none"){this.horizHairline.moveTo([this.props.graph.range[0][0],point[1]],[this.props.graph.range[0][1],point[1]]);this.horizHairline.show();this.vertHairline.moveTo([point[0],this.props.graph.range[1][0]],[point[0],this.props.graph.range[1][1]]);this.vertHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();this.vertHairline.hide();}};}}Grapher.defaultProps=DEFAULT_GRAPHER_PROPS;const propTransform$1=editorProps=>{const widgetProps={availableTypes:editorProps.availableTypes,graph:editorProps.graph};if(widgetProps.availableTypes.length===1){const graph=widgetProps.graph;const type=chooseType(widgetProps.availableTypes);widgetProps.plot=defaultPlotProps(type,graph);}return widgetProps};const staticTransform$4=editorProps=>{return {...propTransform$1(editorProps),availableTypes:[editorProps.correct.type],plot:editorProps.correct}};var Grapher$1 = {name:"grapher",displayName:"Grapher",hidden:true,widget:Grapher,transform:propTransform$1,staticTransform:staticTransform$4};
|
|
1835
1836
|
|
|
1836
1837
|
const getPromptJSON$f=rendererJSON=>{if(!rendererJSON){return {type:"group",content:"",widgets:{}}}return {...rendererJSON,type:"group"}};
|
|
1837
1838
|
|
|
@@ -1893,7 +1894,7 @@ class MultiButtonGroup extends React.Component{focus(){this.buttonContainerRef.c
|
|
|
1893
1894
|
|
|
1894
1895
|
function isPiMultiple(value){if(Number.isInteger(value)){return false}return value%Math.PI===0||value%(Math.PI/2)===0||value%(Math.PI/3)===0||value%(Math.PI/4)===0||value%(Math.PI/6)===0}
|
|
1895
1896
|
|
|
1896
|
-
const{firstNumericalParse,captureScratchpadTouchStart}=Util;const toNumericString=KhanMath.toNumericString;const getNumericFormat=KhanMath.getNumericFormat;class NumberInput extends React.Component{componentDidMount(){const value=this.getValue();if(this.props.allowPiTruncation&&value!==null&&value!==0){if(this.state.format!=="pi"&&isPiMultiple(value)){this._setValue(value/Math.PI,"pi");this.setState({format:"pi"});}}}componentDidUpdate(prevProps){if(!number.equal(this.getValue(),this.props.value)){this._setValue(this.props.value,this.state.format);}}render(){let classes=classNames$1({"number-input":true,"invalid-input":!this._checkValidity(this.props.value),mini:this.props.size==="mini",small:this.props.size==="small",normal:this.props.size==="normal"});if(this.props.className!=null){classes=classes+" "+this.props.className;}const{onFormatChange,checkValidity,useArrowKeys,...restProps}=this.props;return jsxRuntimeExports.jsx("input",{...restProps,className:classes,type:"text",ref:this.inputRef,onChange:this._handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur,onKeyPress:this._handleBlur,onKeyDown:this._onKeyDown,onTouchStart:captureScratchpadTouchStart,defaultValue:toNumericString(this.props.value,this.state.format),value:undefined})}constructor(...args){super(...args),this.inputRef=React.createRef(),this.state={format:this.props.format},this._getInput=()=>{if(!this.inputRef.current){throw new PerseusError("Input ref accessed before set",Errors.Internal)}return this.inputRef.current},this.getValue=()=>{return this.parseInputValue(this._getInput().value)},this.getStringValue=()=>{return this._getInput().toString()},this.parseInputValue=value=>{if(value===""){const placeholder=this.props.placeholder;return _.isFinite(placeholder)?+placeholder:null}const result=firstNumericalParse(value);return _.isFinite(result)?result:this.props.value},this.focus=()=>{this._getInput().focus();this._handleFocus();},this.blur=()=>{this._getInput().blur();this._handleBlur();},this.setSelectionRange=(selectionStart,selectionEnd)=>{this._getInput().setSelectionRange(selectionStart,selectionEnd);},this.getSelectionStart=()=>{return this._getInput().selectionStart},this.getSelectionEnd=()=>{return this._getInput().selectionEnd},this._checkValidity=value=>{if(value==null){return true}const val=firstNumericalParse(value);const checkValidity=this.props.checkValidity;return _.isFinite(val)&&checkValidity(val)},this._handleChange=e=>{const text=e.target.value;const value=this.parseInputValue(text);const format=getNumericFormat(text);this.props.onChange(value);if(format){this.props.onFormatChange(value,format);this.setState({format:format});}},this._handleFocus=()=>{if(this.props.onFocus){this.props.onFocus();}},this._handleBlur=e=>{if(e&&e.type==="keypress"&&e.keyCode!==13){return}this._setValue(this.props.value,this.state.format);if(this.props.onBlur){this.props.onBlur();}},this._onKeyDown=e=>{if(this.props.onKeyDown){this.props.onKeyDown(e);}if(!this.props.useArrowKeys||!_.contains(["ArrowUp","ArrowDown"],e.key)){return}let val=this.getValue();if(val!==Math.floor(val)){return}if(e.key==="ArrowUp"){val=val+1;}else if(e.key==="ArrowDown"){val=val-1;}if(this._checkValidity(val)){this.props.onChange(val);}},this._setValue=(val,format)=>{this._getInput().value=toNumericString(val,format);};}}NumberInput.propTypes={value:PropTypes.number,format:PropTypes.string,placeholder:PropTypes.oneOfType([PropTypes.string,PropTypes.number]),onChange:PropTypes.func.isRequired,onFormatChange:PropTypes.func,checkValidity:PropTypes.func,size:PropTypes.oneOf(["mini","small","normal"]),label:PropTypes.oneOf(["put your labels outside your inputs!"]),allowPiTruncation:PropTypes.bool};NumberInput.defaultProps={value:null,placeholder:null,format:null,onFormatChange:()=>null,checkValidity:()=>true,useArrowKeys:false};
|
|
1897
|
+
const{firstNumericalParse,captureScratchpadTouchStart}=Util;const toNumericString=KhanMath.toNumericString;const getNumericFormat=KhanMath.getNumericFormat;class NumberInput extends React.Component{componentDidMount(){const value=this.getValue();if(this.props.allowPiTruncation&&value!==null&&value!==0){if(this.state.format!=="pi"&&isPiMultiple(value)){this._setValue(value/Math.PI,"pi");this.setState({format:"pi"});}}}componentDidUpdate(prevProps){if(!number.equal(this.getValue(),this.props.value)){this._setValue(this.props.value,this.state.format);}}render(){let classes=classNames$1({"number-input":true,"invalid-input":!this._checkValidity(this.props.value),mini:this.props.size==="mini",small:this.props.size==="small",normal:this.props.size==="normal"});if(this.props.className!=null){classes=classes+" "+this.props.className;}const{onFormatChange:_,checkValidity:__,useArrowKeys:___,allowPiTruncation:____,...restProps}=this.props;return jsxRuntimeExports.jsx("input",{...restProps,className:classes,type:"text",ref:this.inputRef,onChange:this._handleChange,onFocus:this._handleFocus,onBlur:this._handleBlur,onKeyPress:this._handleBlur,onKeyDown:this._onKeyDown,onTouchStart:captureScratchpadTouchStart,defaultValue:toNumericString(this.props.value,this.state.format),value:undefined})}constructor(...args){super(...args),this.inputRef=React.createRef(),this.state={format:this.props.format},this._getInput=()=>{if(!this.inputRef.current){throw new PerseusError("Input ref accessed before set",Errors.Internal)}return this.inputRef.current},this.getValue=()=>{return this.parseInputValue(this._getInput().value)},this.getStringValue=()=>{return this._getInput().toString()},this.parseInputValue=value=>{if(value===""){const placeholder=this.props.placeholder;return _.isFinite(placeholder)?+placeholder:null}const result=firstNumericalParse(value);return _.isFinite(result)?result:this.props.value},this.focus=()=>{this._getInput().focus();this._handleFocus();},this.blur=()=>{this._getInput().blur();this._handleBlur();},this.setSelectionRange=(selectionStart,selectionEnd)=>{this._getInput().setSelectionRange(selectionStart,selectionEnd);},this.getSelectionStart=()=>{return this._getInput().selectionStart},this.getSelectionEnd=()=>{return this._getInput().selectionEnd},this._checkValidity=value=>{if(value==null){return true}const val=firstNumericalParse(value);const checkValidity=this.props.checkValidity;return _.isFinite(val)&&checkValidity(val)},this._handleChange=e=>{const text=e.target.value;const value=this.parseInputValue(text);const format=getNumericFormat(text);this.props.onChange(value);if(format){this.props.onFormatChange(value,format);this.setState({format:format});}},this._handleFocus=()=>{if(this.props.onFocus){this.props.onFocus();}},this._handleBlur=e=>{if(e&&e.type==="keypress"&&e.keyCode!==13){return}this._setValue(this.props.value,this.state.format);if(this.props.onBlur){this.props.onBlur();}},this._onKeyDown=e=>{if(this.props.onKeyDown){this.props.onKeyDown(e);}if(!this.props.useArrowKeys||!_.contains(["ArrowUp","ArrowDown"],e.key)){return}let val=this.getValue();if(val!==Math.floor(val)){return}if(e.key==="ArrowUp"){val=val+1;}else if(e.key==="ArrowDown"){val=val-1;}if(this._checkValidity(val)){this.props.onChange(val);}},this._setValue=(val,format)=>{this._getInput().value=toNumericString(val,format);};}}NumberInput.propTypes={value:PropTypes.number,format:PropTypes.string,placeholder:PropTypes.oneOfType([PropTypes.string,PropTypes.number]),onChange:PropTypes.func.isRequired,onFormatChange:PropTypes.func,checkValidity:PropTypes.func,size:PropTypes.oneOf(["mini","small","normal"]),label:PropTypes.oneOf(["put your labels outside your inputs!"]),allowPiTruncation:PropTypes.bool};NumberInput.defaultProps={value:null,placeholder:null,format:null,onFormatChange:()=>null,checkValidity:()=>true,useArrowKeys:false};
|
|
1897
1898
|
|
|
1898
1899
|
const truth=()=>true;class RangeInput extends React.Component{render(){const value=this.props.value;const checkValidity=this.props.checkValidity||truth;return jsxRuntimeExports.jsxs("div",{className:"range-input",children:[jsxRuntimeExports.jsx(NumberInput,{...this.props,value:value[0],checkValidity:val=>checkValidity([val,value[1]]),onChange:this.onChange.bind(this,0),placeholder:this.props.placeholder[0],allowPiTruncation:this.props.allowPiTruncation}),jsxRuntimeExports.jsx(NumberInput,{...this.props,value:value[1],checkValidity:val=>checkValidity([value[0],val]),onChange:this.onChange.bind(this,1),placeholder:this.props.placeholder[1],allowPiTruncation:this.props.allowPiTruncation})]})}constructor(...args){super(...args),this.onChange=(i,newVal)=>{const value=this.props.value;if(i===0){this.props.onChange([newVal,value[1]]);}else {this.props.onChange([value[0],newVal]);}};}}RangeInput.propTypes={value:PropTypes.array.isRequired,onChange:PropTypes.func.isRequired,placeholder:PropTypes.array,checkValidity:PropTypes.func,allowPiTruncation:PropTypes.bool};RangeInput.defaultProps={placeholder:[null,null]};
|
|
1899
1900
|
|
|
@@ -1918,7 +1919,7 @@ const LegacyGrid=({box,backgroundImage})=>{const{url,width,height}=backgroundIma
|
|
|
1918
1919
|
|
|
1919
1920
|
function LockedLabel(props){const{coord,text,color,size}=props;const[x,y]=pointToPixel(coord,useGraphConfig());const{TeX}=getDependencies();return jsxRuntimeExports.jsx("span",{className:"locked-label",style:{position:"absolute",left:x,top:y,color:lockedFigureColors[color],fontSize:font.size[size],backgroundColor:"rgba(255, 255, 255, 0.8)"},"aria-hidden":true,children:jsxRuntimeExports.jsx(TeX,{children:replaceOutsideTeX(text)})})}
|
|
1920
1921
|
|
|
1921
|
-
function GraphLockedLabelsLayer(props){const{lockedFigures}=props;return lockedFigures.map((figure,i)=>{if(figure.type==="label"){return jsxRuntimeExports.jsx(LockedLabel,{...figure},`label-${i}`)}return jsxRuntimeExports.jsxs(React.Fragment,{children:[figure.labels
|
|
1922
|
+
function GraphLockedLabelsLayer(props){const{lockedFigures}=props;return lockedFigures.map((figure,i)=>{if(figure.type==="label"){return jsxRuntimeExports.jsx(LockedLabel,{...figure},`label-${i}`)}return jsxRuntimeExports.jsxs(React.Fragment,{children:[figure.labels.map((label,j)=>jsxRuntimeExports.jsx(LockedLabel,{...label},`${i}-label-${j}`)),figure.type==="line"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[figure.points[0].labels.map((label,k)=>jsxRuntimeExports.jsx(LockedLabel,{...label},`locked-figure-${i}-point-1-label-${k}`)),figure.points[1].labels.map((label,k)=>jsxRuntimeExports.jsx(LockedLabel,{...label},`locked-figure-${i}-point-2-label-${k}`))]})]},i)})}
|
|
1922
1923
|
|
|
1923
1924
|
const LockedEllipse=props=>{const{center,radius,angle,color: color$1,fillStyle,strokeStyle,ariaLabel}=props;const hasAria=!!ariaLabel;return jsxRuntimeExports.jsx("g",{className:"locked-ellipse","aria-label":hasAria?ariaLabel:undefined,"aria-hidden":!hasAria,role:"img",children:jsxRuntimeExports.jsx(Ellipse,{center:center,radius:radius,angle:angle,fillOpacity:lockedFigureFillStyles[fillStyle],strokeStyle:strokeStyle,color:lockedFigureColors[color$1],svgEllipseProps:{style:{fill:fillStyle==="white"?color.white:lockedFigureColors[color$1]}}})})};
|
|
1924
1925
|
|
|
@@ -1952,20 +1953,6 @@ const TextLabel=({children,...rest})=>jsxRuntimeExports.jsx(Text$1,{size:16,svgT
|
|
|
1952
1953
|
|
|
1953
1954
|
const{clockwise}=geometry;const{getAngleFromVertex: getAngleFromVertex$1}=angles;const PolygonAngle=({centerPoint,endPoints,range,polygonLines,showAngles,snapTo})=>{const[centerX,centerY]=centerPoint;const areClockwise=clockwise([centerPoint,...endPoints]);const[[startX,startY],[endX,endY]]=areClockwise?endPoints:endPoints.reverse();const radius=.3;const a=vec.dist(centerPoint,endPoints[0]);const b=vec.dist(centerPoint,endPoints[1]);const c=vec.dist(endPoints[0],endPoints[1]);let lawOfCosinesRadicand=(a**2+b**2-c**2)/(2*a*b);if(lawOfCosinesRadicand<-1||lawOfCosinesRadicand>1){lawOfCosinesRadicand=Math.round(lawOfCosinesRadicand);}const angle=Math.acos(lawOfCosinesRadicand);const y1=centerY+(startY-centerY)/a*radius;const x2=centerX+(endX-centerX)/b*radius;const x1=centerX+(startX-centerX)/a*radius;const y2=centerY+(endY-centerY)/b*radius;const[x3,y3]=vec.add(centerPoint,vec.add(vec.sub([x1,y1],centerPoint),vec.sub([x2,y2],centerPoint)));if(!showAngles){return isRightPolygonAngle(angle)?jsxRuntimeExports.jsx(RightAngleSquare,{start:[x1,y1],vertex:[x2,y2],end:[x3,y3]}):null}const isOutside=shouldDrawArcOutside([x3,y3],centerPoint,range,polygonLines);const largeArcFlag=isOutside?1:0;const sweepFlag=isOutside?1:0;const arc=`M ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} ${sweepFlag} ${x2} ${y2}`;let angleInDegrees=angle*(180/Math.PI);if(isOutside){angleInDegrees=360-angleInDegrees;}const angleLabelNumber=parseFloat(angleInDegrees.toFixed(snapTo==="angles"?0:1));const angleLabel=Number.isInteger(angleLabelNumber)?angleLabelNumber:"≈ "+angleLabelNumber;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("defs",{children:jsxRuntimeExports.jsxs("filter",{id:"background",x:"-5%",width:"110%",y:"0%",height:"100%",children:[jsxRuntimeExports.jsx("feFlood",{floodColor:"#FFF",floodOpacity:"0.5"}),jsxRuntimeExports.jsx("feComposite",{operator:"over",in:"SourceGraphic"})]})}),!isOutside&&isRightPolygonAngle(angle)?jsxRuntimeExports.jsx(RightAngleSquare,{start:[x1,y1],vertex:[x2,y2],end:[x3,y3]}):jsxRuntimeExports.jsx(Arc,{arc:arc}),jsxRuntimeExports.jsxs(TextLabel,{x:x3,y:y3,attach:y3-centerY>0?"s":"n",attachDistance:Math.abs(y3-centerY)<.2||vec.dist([x3,y3],centerPoint)<.3?20:10,children:[angleLabel,"°"]})]})};const Angle=({vertex,coords,showAngles,allowReflexAngles,range})=>{const areClockwise=clockwise([...coords,vertex]);const shouldReverseCoords=areClockwise&&!allowReflexAngles;const clockwiseCoords=shouldReverseCoords?coords:coords.reverse();const startAngle=getAngleFromVertex$1(clockwiseCoords[0],vertex);const endAngle=getAngleFromVertex$1(clockwiseCoords[1],vertex);const angle=(startAngle+360-endAngle)%360;const isReflexive=angle>180;const[centerX,centerY]=vertex;const[point1,point2]=clockwiseCoords;const[startX,startY]=point1;const[endX,endY]=point2;const a=vec.dist(vertex,point1);const b=vec.dist(vertex,point2);const radius=2;const y1=centerY+(startY-centerY)/a*radius;const x2=centerX+(endX-centerX)/b*radius;const x1=centerX+(startX-centerX)/a*radius;const y2=centerY+(endY-centerY)/b*radius;const[x3,y3]=vec.add(vertex,vec.add(vec.sub([x1,y1],vertex),vec.sub([x2,y2],vertex)));const isOutside=shouldDrawArcOutside([x3,y3],vertex,range,[[vertex,point1],[vertex,point2]]);const largeArcFlag=isOutside||isReflexive?1:0;const sweepFlag=isOutside&&isReflexive?1:0;const arc=`M ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} ${sweepFlag} ${x2} ${y2}`;const angleLabel=parseFloat(angle.toFixed(0));const[textX,textY]=calculateBisectorPoint(point1,point2,vertex,isReflexive,allowReflexAngles,radius);const{disableKeyboardInteraction}=useGraphConfig();const arcClassName=disableKeyboardInteraction?"angle-arc-static":"angle-arc-interactive";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("defs",{children:jsxRuntimeExports.jsxs("filter",{id:"background",x:"-5%",width:"110%",y:"0%",height:"100%",children:[jsxRuntimeExports.jsx("feFlood",{floodColor:"#FFF",floodOpacity:"0.5"}),jsxRuntimeExports.jsx("feComposite",{operator:"over",in:"SourceGraphic"})]})}),isRightAngle(angle)?jsxRuntimeExports.jsx(RightAngleSquare,{start:[x1,y1],vertex:[x2,y2],end:[x3,y3],className:arcClassName}):jsxRuntimeExports.jsx(Arc,{arc:arc,className:arcClassName}),showAngles&&jsxRuntimeExports.jsxs(TextLabel,{x:textX,y:textY,color:color.blue,children:[angleLabel,"°"]})]})};const RightAngleSquare=({start:[x1,y1],vertex:[x2,y2],end:[x3,y3],className})=>jsxRuntimeExports.jsx(MafsCssTransformWrapper,{children:jsxRuntimeExports.jsx("path",{"aria-hidden":true,d:`M ${x1} ${y1} L ${x3} ${y3} M ${x3} ${y3} L ${x2} ${y2}`,strokeWidth:.02,fill:"none",className:className,"data-testid":"angle-indicators__right-angle"})});const Arc=({arc,className})=>{return jsxRuntimeExports.jsx(MafsCssTransformWrapper,{children:jsxRuntimeExports.jsx("path",{"aria-hidden":true,d:arc,strokeWidth:.02,fill:"none",className:className,"data-testid":"angle-indicators__arc"})})};const isRightPolygonAngle=angle=>Math.abs(angle-Math.PI/2)<.01;const isRightAngle=angle=>Math.round(angle)===90;const shouldDrawArcOutside=(midpoint,vertex,range,polygonLines)=>{const rangeIntersectionPoint=getIntersectionOfRayWithBox(midpoint,vertex,range);let lineIntersectionCount=0;polygonLines.forEach(line=>segmentsIntersect([vertex,rangeIntersectionPoint],line)&&lineIntersectionCount++);return !isEven(lineIntersectionCount)};const isEven=n=>n%2===0;function calculateBisectorPoint(point1,point2,vertex,isReflex,allowReflex,arcRadius){const[originX,originY]=vertex;const[x1,y1]=point1;const[x2,y2]=point2;const vectorA=[x1-originX,y1-originY];const vectorB=[x2-originX,y2-originY];const angleA=Math.atan2(vectorA[1],vectorA[0]);const angleB=Math.atan2(vectorB[1],vectorB[0]);let averageAngle=(angleA+angleB)/2;const angleRadians=Math.abs(angleA-angleB);if(allowReflex){if(angleRadians<=Math.PI&&isReflex||angleB>angleA){averageAngle+=Math.PI;}}else {if(angleRadians>Math.PI){averageAngle-=Math.PI;}}const sum=[Math.cos(averageAngle),Math.sin(averageAngle)];const sumMagnitude=Math.sqrt(sum[0]**2+sum[1]**2);const bisectorDirection=[sum[0]/sumMagnitude,sum[1]/sumMagnitude];const initialDistance=Math.sqrt(bisectorDirection[0]**2+bisectorDirection[1]**2);const requiredDistance=arcRadius*1.75;let radius=requiredDistance/initialDistance;if(initialDistance>=requiredDistance){radius=1;}const bisectorPoint=[bisectorDirection[0]*radius,bisectorDirection[1]*radius];const scaledBisector=vec.add(bisectorPoint,vertex);return scaledBisector}
|
|
1954
1955
|
|
|
1955
|
-
var isProduction = process.env.NODE_ENV === 'production';
|
|
1956
|
-
var prefix = 'Invariant failed';
|
|
1957
|
-
function invariant(condition, message) {
|
|
1958
|
-
if (condition) {
|
|
1959
|
-
return;
|
|
1960
|
-
}
|
|
1961
|
-
if (isProduction) {
|
|
1962
|
-
throw new Error(prefix);
|
|
1963
|
-
}
|
|
1964
|
-
var provided = typeof message === 'function' ? message() : message;
|
|
1965
|
-
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
1966
|
-
throw new Error(value);
|
|
1967
|
-
}
|
|
1968
|
-
|
|
1969
1956
|
function useDraggable(args){const{gestureTarget:target,onMove,point,constrainKeyboardMovement}=args;const[dragging,setDragging]=React.useState(false);const{xSpan,ySpan}=useSpanContext();const{viewTransform,userTransform}=useTransformContext();const inverseViewTransform=vec.matrixInvert(viewTransform);invariant(inverseViewTransform,"The view transform must be invertible.");const inverseTransform=React.useMemo(()=>getInverseTransform(userTransform),[userTransform]);const pickup=React.useRef([0,0]);useDrag(state=>{const{type,event}=state;event?.stopPropagation();const isKeyboard=type.includes("key");if(isKeyboard){invariant(event instanceof KeyboardEvent);event?.preventDefault();if(type==="keyup"){return}if(typeof constrainKeyboardMovement==="object"){const destination=constrainKeyboardMovement[directionForKey[event.key]];onMove(destination??point);return}const{direction:yDownDirection,altKey,ctrlKey,metaKey,shiftKey}=state;const direction=[yDownDirection[X],-yDownDirection[Y]];const span=Math.abs(direction[X])?xSpan:ySpan;let divisions=50;if(altKey||metaKey){divisions=200;}if(shiftKey&&!ctrlKey){divisions=10;}const min=span/(divisions*2);const tests=range(span/divisions,span/2,span/divisions);for(const dx of tests){const testMovement=vec.scale(direction,dx);const testPoint=constrainKeyboardMovement(vec.transform(vec.add(vec.transform(point,userTransform),testMovement),inverseTransform));if(vec.dist(testPoint,point)>min){onMove(testPoint);break}}}else {const{last,movement:pixelMovement,first}=state;setDragging(!last);if(first){pickup.current=vec.transform(point,userTransform);}if(vec.mag(pixelMovement)===0){return}const movement=vec.transform(pixelMovement,inverseViewTransform);onMove(vec.transform(vec.add(pickup.current,movement),inverseTransform));}},{target,eventOptions:{passive:false}});return {dragging}}const directionForKey={ArrowLeft:"left",ArrowRight:"right",ArrowUp:"up",ArrowDown:"down"};function getInverseTransform(transform){const invert=vec.matrixInvert(transform);invariant(invert!==null,"Could not invert transform matrix. A parent transformation matrix might be degenerative (mapping 2D space to a line).");return invert}function useSpanContext(){const{range:[[xMin,xMax],[yMin,yMax]]}=useGraphConfig();const xSpan=xMax-xMin;const ySpan=yMax-yMin;return {xSpan,ySpan}}function range(min,max,step=1){const result=[];for(let i=min;i<max-step/2;i+=step){result.push(i);}const computedMax=result[result.length-1]+step;if(Math.abs(max-computedMax)<step/1e-6){result.push(max);}else {result.push(computedMax);}return result}
|
|
1970
1957
|
|
|
1971
1958
|
function Hairlines(props){const{point}=props;const{range}=useGraphConfig();const[[xMin,xMax],[yMin,yMax]]=range;const[[x,y]]=useTransformVectorsToPixels(point);const[[verticalStartX]]=useTransformVectorsToPixels([xMin,0]);const[[verticalEndX]]=useTransformVectorsToPixels([xMax,0]);const[[_,horizontalStartY]]=useTransformVectorsToPixels([0,yMin]);const[[__,horizontalEndY]]=useTransformVectorsToPixels([0,yMax]);return jsxRuntimeExports.jsxs("g",{"aria-hidden":true,children:[jsxRuntimeExports.jsx("line",{x1:verticalStartX,y1:y,x2:verticalEndX,y2:y,stroke:color.blue}),jsxRuntimeExports.jsx("line",{x1:x,y1:horizontalStartY,x2:x,y2:horizontalEndY,stroke:color.blue})]})}
|
|
@@ -2008,7 +1995,7 @@ function renderSinusoidGraph(state,dispatch,i18n){return {graph:jsxRuntimeExport
|
|
|
2008
1995
|
|
|
2009
1996
|
const{calculateAngleInDegrees,convertDegreesToRadians}=angles;const protractorImage="https://cdn.kastatic.org/images/perseus/protractor.svg";const centerToTopLeft=[-195,-190];const centerToRotationHandle=[-201,-15];function Protractor(){const staticUrl=getDependencies().staticUrl;const{range,snapStep}=useGraphConfig();const[[xMin,xMax],[yMin,yMax]]=range;const initialCenter=[lerp(xMin,xMax,.5),lerp(yMin,yMax,.25)];const[center,setCenter]=useState(initialCenter);const[rotationHandleOffset,setRotationHandleOffset]=useState(centerToRotationHandle);const draggableRef=useRef(null);const{dragging}=useDraggable({gestureTarget:draggableRef,onMove:setCenter,point:center,constrainKeyboardMovement:point=>bound$1({snapStep,range,point})});const rotationHandleRef=useRef(null);useDraggablePx({gestureTarget:rotationHandleRef,onMove:setRotationHandleOffset,point:rotationHandleOffset,constrain:constrainToCircle});const[centerPx]=useTransformVectorsToPixels(center);const topLeftPx=vec.add(centerPx,centerToTopLeft);const angle=calculateAngleInDegrees(rotationHandleOffset)-calculateAngleInDegrees(centerToRotationHandle);return jsxRuntimeExports.jsxs("g",{ref:draggableRef,transform:`translate(${topLeftPx[X]}, ${topLeftPx[Y]}), rotate(${angle})`,style:{transformOrigin:`${-centerToTopLeft[X]}px ${-centerToTopLeft[Y]}px`,cursor:dragging?"grabbing":"grab"},children:[jsxRuntimeExports.jsx("image",{href:staticUrl(protractorImage)}),jsxRuntimeExports.jsx("g",{transform:`translate(5, ${-centerToTopLeft[1]})`,ref:rotationHandleRef,children:jsxRuntimeExports.jsx(RotationArrow,{})})]})}function RotationArrow(){const radius=175;const angleDeg=10;const angleRad=convertDegreesToRadians(angleDeg);const endX=radius*(1-Math.cos(angleRad));const endY=radius*-Math.sin(angleRad);const rotationArrow=pathBuilder().move(0,0).circularArc(radius,endX,endY,{sweep:true}).build();const arrowhead=pathBuilder().move(-8,0).line(0,10).line(8,0).build();const targetRadius=TARGET_SIZE/2;return jsxRuntimeExports.jsxs("g",{className:"protractor-rotation-handle",children:[jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrow-arc",d:rotationArrow}),jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrowhead",d:arrowhead}),jsxRuntimeExports.jsx("path",{className:"protractor-rotation-handle-arrowhead",d:arrowhead,transform:`translate(${endX}, ${endY}), rotate(${180+angleDeg})`}),jsxRuntimeExports.jsx("ellipse",{cx:"0px",cy:"-15px",rx:targetRadius,ry:targetRadius,fill:"none"})]})}const protractorRadius=vec.mag(centerToRotationHandle);function constrainToCircle(edgePoint){return vec.withMag(edgePoint,protractorRadius)}function useDraggablePx(args){const{gestureTarget:target,onMove,point,constrain=p=>p}=args;const pickupPx=React.useRef([0,0]);useDrag(state=>{const{event,first,movement:pixelMovement}=state;event?.stopPropagation();if(first){pickupPx.current=point;}if(vec.mag(pixelMovement)===0){return}onMove?.(constrain(vec.add(pickupPx.current,pixelMovement)));},{target,eventOptions:{passive:false}});}
|
|
2010
1997
|
|
|
2011
|
-
const MafsGraph=props=>{const{state,dispatch,labels,labelLocation,readOnly,fullGraphAriaLabel,fullGraphAriaDescription}=props;const{type}=state;const[width,height]=props.box;const tickStep=props.step;const uniqueId=React.useId();const descriptionId=`interactive-graph-description-${uniqueId}`;const interactiveElementsDescriptionId=`interactive-graph-interactive-elements-description-${uniqueId}`;const unlimitedGraphKeyboardPromptId=`unlimited-graph-keyboard-prompt-${uniqueId}`;const instructionsId=`instructions-${uniqueId}`;const graphRef=React.useRef(null);const{analytics}=useDependencies();const{viewboxX,viewboxY}=calculateNestedSVGCoords(state.range,width,height);const viewBox=`${viewboxX} ${viewboxY} ${width} ${height}`;const nestedSVGAttributes={width,height,viewBox,preserveAspectRatio:"xMidYMin",x:viewboxX,y:viewboxY};const i18n=usePerseusI18n();const{strings}=i18n;const interactionPrompt=isUnlimitedGraphState(state)&&state.showKeyboardInteractionInvitation;useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:interactive-graph-widget:rendered",payload:{type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});});const{graph,interactiveElementsDescription}=renderGraphElements({state,dispatch,i18n,markings:props.markings});const disableInteraction=readOnly||!!props.static;return jsxRuntimeExports.jsx(GraphConfigContext.Provider,{value:{range:state.range,snapStep:state.snapStep,markings:props.markings,tickStep:tickStep,gridStep:props.gridStep,showTooltips:!!props.showTooltips,graphDimensionsInPixels:props.box,width,height,labels,labelLocation,disableKeyboardInteraction:disableInteraction,interactiveColor:disableInteraction?"var(--static-gray)":"var(--mafs-blue)"},children:jsxRuntimeExports.jsxs(View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(View,{className:"mafs-graph",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:"20px",marginBottom:"30px",pointerEvents:props.static?"none":"auto",userSelect:"none",width,height},onKeyUp:event=>{handleKeyboardEvent(event,state,dispatch);},"aria-label":fullGraphAriaLabel,"aria-describedby":describedByIds(fullGraphAriaDescription&&descriptionId,interactiveElementsDescription&&interactiveElementsDescriptionId,isUnlimitedGraphState(state)&&unlimitedGraphKeyboardPromptId,state.type!=="none"&&!disableInteraction&&instructionsId),ref:graphRef,tabIndex:0,onFocus:event=>{handleFocusEvent(event,state,dispatch);},onBlur:event=>{handleBlurEvent(event,state,dispatch);},children:[fullGraphAriaDescription&&jsxRuntimeExports.jsx(View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),state.type!=="none"&&jsxRuntimeExports.jsx(View,{id:instructionsId,tabIndex:-1,className:"mafs-sr-only",children:isUnlimitedGraphState(state)?strings.srUnlimitedGraphInstructions:strings.srGraphInstructions}),jsxRuntimeExports.jsx(LegacyGrid,{box:props.box,backgroundImage:props.backgroundImage}),jsxRuntimeExports.jsxs(View,{style:{position:"absolute",bottom:0,left:0},children:[(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx(AxisLabels,{i18n:i18n})}),jsxRuntimeExports.jsx(View,{"aria-hidden":props.lockedFigures&&props.lockedFigures.length>0?false:true,children:jsxRuntimeExports.jsxs(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[jsxRuntimeExports.jsx(SvgDefs,{}),jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(Grid,{gridStep:props.gridStep,range:state.range,containerSizeClass:props.containerSizeClass,markings:props.markings,width:width,height:height})}),(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(AxisTicks,{}),jsxRuntimeExports.jsx(AxisArrows,{})]}),props.lockedFigures&&props.lockedFigures.length>0&&jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(GraphLockedLayer,{lockedFigures:props.lockedFigures,range:state.range})})]})}),props.lockedFigures&&jsxRuntimeExports.jsx(GraphLockedLabelsLayer,{lockedFigures:props.lockedFigures}),jsxRuntimeExports.jsx(View,{style:{position:"absolute"},children:jsxRuntimeExports.jsx(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:jsxRuntimeExports.jsxs("svg",{...nestedSVGAttributes,children:[props.showProtractor&&jsxRuntimeExports.jsx(Protractor,{}),graph]})})})]}),interactionPrompt&&jsxRuntimeExports.jsx(View,{style:{display:interactionPrompt?undefined:"hidden",textAlign:"center",backgroundColor:"white",border:"1px solid #21242C52",padding:"16px 0",boxShadow:"0px 8px 8px 0px #21242C14",top:"50%",transform:"translateY(-50%)"},children:jsxRuntimeExports.jsx(LabelMedium,{id:unlimitedGraphKeyboardPromptId,children:strings.graphKeyboardPrompt})})]}),renderGraphControls({state,dispatch,width,perseusStrings:strings})]})})};const renderPointGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;return jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.pointGraph.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",color:"destructive",tabIndex:-1,style:{width:"100%",marginLeft:"20px",visibility:shouldShowRemoveButton?"visible":"hidden"},onClick:_event=>{props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint})]})};const renderPolygonGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex,closedPolygon,coords}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;const disableCloseButton=getArrayWithoutDuplicates(coords).length<3;const polygonButton=closedPolygon?jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:disableCloseButton,style:{width:"100%",marginLeft:"20px"},tabIndex:disableCloseButton?-1:0,onClick:()=>{props.dispatch(actions.polygon.closePolygon());},children:perseusStrings.closePolygon});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},disabled:closedPolygon,tabIndex:closedPolygon?-1:0,onClick:()=>{props.dispatch(actions.polygon.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",color:"destructive",disabled:closedPolygon||!shouldShowRemoveButton,tabIndex:-1,style:{width:"100%",marginLeft:"20px"},onClick:_event=>{props.dispatch(actions.polygon.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint}),polygonButton]})})};const renderGraphControls=props=>{const{state,dispatch,width,perseusStrings}=props;const{type}=state;switch(type){case "point":if(state.numPoints==="unlimited"){return renderPointGraphControls({state,dispatch,width,perseusStrings})}return null;case "polygon":if(state.numSides==="unlimited"){return renderPolygonGraphControls({state,dispatch,width,perseusStrings})}return null;default:return null}};function handleFocusEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.target.classList.contains("mafs-graph")&&state.interactionMode==="mouse"){dispatch(actions.global.changeKeyboardInvitationVisibility(true));}}}function handleBlurEvent(_event,state,dispatch){if(isUnlimitedGraphState(state)){dispatch(actions.global.changeKeyboardInvitationVisibility(false));}}function handleKeyboardEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.key==="Backspace"||event.key==="Delete"){if(document.activeElement?.classList.contains("movable-point__focusable-handle")){if(state.type==="point"||state.type==="polygon"&&!state.closedPolygon){dispatch(actions.global.deleteIntent());}}document.activeElement.blur();}else if(event.shiftKey&&event.key==="Enter"){dispatch(actions.global.changeInteractionMode("keyboard"));}else if(state.interactionMode==="keyboard"&&event.key==="a"){dispatch(actions.pointGraph.addPoint([0,0]));}}}const getRangeDiff=range=>{const[min,max]=range;return Math.abs(max-min)};const calculateNestedSVGCoords=(range,width,height)=>{let viewboxX=0;const totalXRange=getRangeDiff(range[X]);const gridCellWidth=width/totalXRange;const minX=range[X][MIN];if(minX>0){viewboxX=gridCellWidth*Math.abs(minX);}if(minX<0){viewboxX=-gridCellWidth*Math.abs(minX);}let viewboxY=-height;const totalYRange=getRangeDiff(range[Y]);const gridCellHeight=height/totalYRange;const minY=range[Y][MIN];if(minY>0){viewboxY=-height-gridCellHeight*Math.abs(minY);}if(minY<0){viewboxY=gridCellHeight*Math.abs(minY)-height;}return {viewboxX,viewboxY}};const renderGraphElements=props=>{const{state,dispatch,i18n,markings}=props;const{type}=state;switch(type){case "angle":return renderAngleGraph(state,dispatch,i18n);case "segment":return renderSegmentGraph(state,dispatch,i18n);case "linear-system":return renderLinearSystemGraph(state,dispatch,i18n);case "linear":return renderLinearGraph(state,dispatch,i18n);case "ray":return renderRayGraph(state,dispatch,i18n);case "polygon":return renderPolygonGraph(state,dispatch,i18n,markings);case "point":return renderPointGraph(state,dispatch,i18n);case "circle":return renderCircleGraph(state,dispatch,i18n);case "quadratic":return renderQuadraticGraph(state,dispatch,i18n);case "sinusoid":return renderSinusoidGraph(state,dispatch,i18n);case "none":return {graph:null,interactiveElementsDescription:null};default:throw new UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
|
|
1998
|
+
const MafsGraph=props=>{const{state,dispatch,labels,labelLocation,readOnly,fullGraphAriaLabel,fullGraphAriaDescription}=props;const{type}=state;const[width,height]=props.box;const tickStep=props.step;const uniqueId=React.useId();const descriptionId=`interactive-graph-description-${uniqueId}`;const interactiveElementsDescriptionId=`interactive-graph-interactive-elements-description-${uniqueId}`;const unlimitedGraphKeyboardPromptId=`unlimited-graph-keyboard-prompt-${uniqueId}`;const instructionsId=`instructions-${uniqueId}`;const graphRef=React.useRef(null);const{analytics}=useDependencies();const{viewboxX,viewboxY}=calculateNestedSVGCoords(state.range,width,height);const viewBox=`${viewboxX} ${viewboxY} ${width} ${height}`;const nestedSVGAttributes={width,height,viewBox,preserveAspectRatio:"xMidYMin",x:viewboxX,y:viewboxY};const i18n=usePerseusI18n();const{strings}=i18n;const interactionPrompt=isUnlimitedGraphState(state)&&state.showKeyboardInteractionInvitation;useOnMountEffect(()=>{analytics.onAnalyticsEvent({type:"perseus:interactive-graph-widget:rendered",payload:{type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});analytics.onAnalyticsEvent({type:"perseus:widget:rendered:ti",payload:{widgetSubType:type,widgetType:"INTERACTIVE_GRAPH",widgetId:"interactive-graph"}});});const{graph,interactiveElementsDescription}=renderGraphElements({state,dispatch,i18n,markings:props.markings});const disableInteraction=readOnly||!!props.static;return jsxRuntimeExports.jsx(GraphConfigContext.Provider,{value:{range:state.range,snapStep:state.snapStep,markings:props.markings,tickStep:tickStep,gridStep:props.gridStep,showTooltips:!!props.showTooltips,graphDimensionsInPixels:props.box,width,height,labels,labelLocation,disableKeyboardInteraction:disableInteraction,interactiveColor:disableInteraction?"var(--static-gray)":"var(--mafs-blue)"},children:jsxRuntimeExports.jsxs(View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(View,{className:"mafs-graph",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:"20px",marginBottom:"30px",pointerEvents:props.static?"none":"auto",userSelect:"none",width,height},onKeyUp:event=>{handleKeyboardEvent(event,state,dispatch);},"aria-label":fullGraphAriaLabel,"aria-describedby":describedByIds(fullGraphAriaDescription&&descriptionId,interactiveElementsDescription&&interactiveElementsDescriptionId,isUnlimitedGraphState(state)&&unlimitedGraphKeyboardPromptId,state.type!=="none"&&!disableInteraction&&instructionsId),ref:graphRef,tabIndex:0,onFocus:event=>{handleFocusEvent(event,state,dispatch);},onBlur:event=>{handleBlurEvent(event,state,dispatch);},children:[fullGraphAriaDescription&&jsxRuntimeExports.jsx(View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),state.type!=="none"&&jsxRuntimeExports.jsx(View,{id:instructionsId,tabIndex:-1,className:"mafs-sr-only",children:isUnlimitedGraphState(state)?strings.srUnlimitedGraphInstructions:strings.srGraphInstructions}),jsxRuntimeExports.jsx(LegacyGrid,{box:props.box,backgroundImage:props.backgroundImage}),jsxRuntimeExports.jsxs(View,{style:{position:"absolute",bottom:0,left:0},children:[(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx(AxisLabels,{i18n:i18n})}),jsxRuntimeExports.jsx(View,{"aria-hidden":props.lockedFigures.length===0,children:jsxRuntimeExports.jsxs(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:[jsxRuntimeExports.jsx(SvgDefs,{}),jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(Grid,{gridStep:props.gridStep,range:state.range,containerSizeClass:props.containerSizeClass,markings:props.markings,width:width,height:height})}),(props.markings==="graph"||props.markings==="axes")&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(AxisTicks,{}),jsxRuntimeExports.jsx(AxisArrows,{})]}),props.lockedFigures.length>0&&jsxRuntimeExports.jsx("svg",{...nestedSVGAttributes,children:jsxRuntimeExports.jsx(GraphLockedLayer,{lockedFigures:props.lockedFigures,range:state.range})})]})}),jsxRuntimeExports.jsx(GraphLockedLabelsLayer,{lockedFigures:props.lockedFigures}),jsxRuntimeExports.jsx(View,{style:{position:"absolute"},children:jsxRuntimeExports.jsx(Mafs,{preserveAspectRatio:false,viewBox:{x:state.range[X],y:state.range[Y],padding:0},pan:false,zoom:false,width:width,height:height,children:jsxRuntimeExports.jsxs("svg",{...nestedSVGAttributes,children:[props.showProtractor&&jsxRuntimeExports.jsx(Protractor,{}),graph]})})})]}),interactionPrompt&&jsxRuntimeExports.jsx(View,{style:{display:interactionPrompt?undefined:"hidden",textAlign:"center",backgroundColor:"white",border:"1px solid #21242C52",padding:"16px 0",boxShadow:"0px 8px 8px 0px #21242C14",top:"50%",transform:"translateY(-50%)"},children:jsxRuntimeExports.jsx(LabelMedium,{id:unlimitedGraphKeyboardPromptId,children:strings.graphKeyboardPrompt})})]}),renderGraphControls({state,dispatch,width,perseusStrings:strings})]})})};const renderPointGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;return jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.pointGraph.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",color:"destructive",tabIndex:-1,style:{width:"100%",marginLeft:"20px",visibility:shouldShowRemoveButton?"visible":"hidden"},onClick:_event=>{props.dispatch(actions.pointGraph.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint})]})};const renderPolygonGraphControls=props=>{const{interactionMode,showRemovePointButton,focusedPointIndex,closedPolygon,coords}=props.state;const{perseusStrings}=props;const shouldShowRemoveButton=showRemovePointButton&&focusedPointIndex!==null;const disableCloseButton=getArrayWithoutDuplicates(coords).length<3;const polygonButton=closedPolygon?jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:disableCloseButton,style:{width:"100%",marginLeft:"20px"},tabIndex:disableCloseButton?-1:0,onClick:()=>{props.dispatch(actions.polygon.closePolygon());},children:perseusStrings.closePolygon});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},disabled:closedPolygon,tabIndex:closedPolygon?-1:0,onClick:()=>{props.dispatch(actions.polygon.addPoint([0,0]));},children:perseusStrings.addPoint}),interactionMode==="mouse"&&jsxRuntimeExports.jsx(Button,{id:REMOVE_BUTTON_ID,kind:"secondary",color:"destructive",disabled:closedPolygon||!shouldShowRemoveButton,tabIndex:-1,style:{width:"100%",marginLeft:"20px"},onClick:_event=>{props.dispatch(actions.polygon.removePoint(props.state.focusedPointIndex));},children:perseusStrings.removePoint}),polygonButton]})})};const renderGraphControls=props=>{const{state,dispatch,width,perseusStrings}=props;const{type}=state;switch(type){case "point":if(state.numPoints==="unlimited"){return renderPointGraphControls({state,dispatch,width,perseusStrings})}return null;case "polygon":if(state.numSides==="unlimited"){return renderPolygonGraphControls({state,dispatch,width,perseusStrings})}return null;default:return null}};function handleFocusEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.target.classList.contains("mafs-graph")&&state.interactionMode==="mouse"){dispatch(actions.global.changeKeyboardInvitationVisibility(true));}}}function handleBlurEvent(_event,state,dispatch){if(isUnlimitedGraphState(state)){dispatch(actions.global.changeKeyboardInvitationVisibility(false));}}function handleKeyboardEvent(event,state,dispatch){if(isUnlimitedGraphState(state)){if(event.key==="Backspace"||event.key==="Delete"){if(document.activeElement?.classList.contains("movable-point__focusable-handle")){if(state.type==="point"||state.type==="polygon"&&!state.closedPolygon){dispatch(actions.global.deleteIntent());}}document.activeElement.blur();}else if(event.shiftKey&&event.key==="Enter"){dispatch(actions.global.changeInteractionMode("keyboard"));}else if(state.interactionMode==="keyboard"&&event.key==="a"){dispatch(actions.pointGraph.addPoint([0,0]));}}}const getRangeDiff=range=>{const[min,max]=range;return Math.abs(max-min)};const calculateNestedSVGCoords=(range,width,height)=>{let viewboxX=0;const totalXRange=getRangeDiff(range[X]);const gridCellWidth=width/totalXRange;const minX=range[X][MIN];if(minX>0){viewboxX=gridCellWidth*Math.abs(minX);}if(minX<0){viewboxX=-gridCellWidth*Math.abs(minX);}let viewboxY=-height;const totalYRange=getRangeDiff(range[Y]);const gridCellHeight=height/totalYRange;const minY=range[Y][MIN];if(minY>0){viewboxY=-height-gridCellHeight*Math.abs(minY);}if(minY<0){viewboxY=gridCellHeight*Math.abs(minY)-height;}return {viewboxX,viewboxY}};const renderGraphElements=props=>{const{state,dispatch,i18n,markings}=props;const{type}=state;switch(type){case "angle":return renderAngleGraph(state,dispatch,i18n);case "segment":return renderSegmentGraph(state,dispatch,i18n);case "linear-system":return renderLinearSystemGraph(state,dispatch,i18n);case "linear":return renderLinearGraph(state,dispatch,i18n);case "ray":return renderRayGraph(state,dispatch,i18n);case "polygon":return renderPolygonGraph(state,dispatch,i18n,markings);case "point":return renderPointGraph(state,dispatch,i18n);case "circle":return renderCircleGraph(state,dispatch,i18n);case "quadratic":return renderQuadraticGraph(state,dispatch,i18n);case "sinusoid":return renderSinusoidGraph(state,dispatch,i18n);case "none":return {graph:null,interactiveElementsDescription:null};default:throw new UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
|
|
2012
1999
|
|
|
2013
2000
|
function mafsStateToInteractiveGraph(state,originalGraph){switch(state.type){case "angle":invariant(originalGraph.type==="angle");return {...originalGraph,coords:state.coords};case "quadratic":invariant(originalGraph.type==="quadratic");return {...originalGraph,coords:state.coords};case "circle":invariant(originalGraph.type==="circle");return {...originalGraph,center:state.center,radius:getRadius(state)};case "linear":invariant(originalGraph.type==="linear");return {...originalGraph,coords:state.coords};case "ray":invariant(originalGraph.type==="ray");return {...originalGraph,coords:state.coords};case "sinusoid":invariant(originalGraph.type==="sinusoid");return {...originalGraph,coords:state.coords};case "segment":invariant(originalGraph.type==="segment");return {...originalGraph,coords:state.coords};case "linear-system":invariant(originalGraph.type==="linear-system");return {...originalGraph,coords:state.coords};case "polygon":invariant(originalGraph.type==="polygon");return {...originalGraph,coords:state.coords};case "point":invariant(originalGraph.type==="point");return {...originalGraph,coords:state.coords};case "none":invariant(originalGraph.type==="none");return {...originalGraph};default:throw new UnreachableCaseError(state)}}
|
|
2014
2001
|
|
|
@@ -2038,7 +2025,7 @@ const HACKY_CSS_CLASSNAME="perseus-widget-matcher";class Matcher extends React.C
|
|
|
2038
2025
|
|
|
2039
2026
|
const getPromptJSON$8=(renderProps,userInput)=>{return {type:"matrix",options:{height:renderProps.matrixBoardSize[0],width:renderProps.matrixBoardSize[1]},userInput:{answerRows:userInput.answers}}};
|
|
2040
2027
|
|
|
2041
|
-
const{assert: assert$2}=InteractiveUtil;const
|
|
2028
|
+
const{assert: assert$2}=InteractiveUtil;const NORMAL_DIMENSIONS={INPUT_MARGIN:3,INPUT_HEIGHT:30,INPUT_WIDTH:40};const KEYPAD_INPUT_DIMENSIONS={INPUT_MARGIN:4,INPUT_HEIGHT:36,INPUT_WIDTH:64};function getInputPath$1(row,column){return [""+row,""+column]}const getDefaultPath$1=function(){return getInputPath$1(0,0)};const getRowFromPath$1=function(path){assert$2(Array.isArray(path)&&path.length===2);return +path[0]};const getColumnFromPath$1=function(path){assert$2(Array.isArray(path)&&path.length===2);return +path[1]};const getRefForPath$1=function(path){const row=getRowFromPath$1(path);const column=getColumnFromPath$1(path);return "answer"+row+","+column};class Matrix extends React.Component{componentDidMount(){this.cursorPosition=[0,0];}getDOMNodeForPath(path){const inputID=getRefForPath$1(path);return ReactDOM__default.findDOMNode(this.refs[inputID])}getUserInput(){return {answers:this.props.answers}}getPromptJSON(){return getPromptJSON$8(this.props,this.getUserInput())}render(){let dimensions;if(this.props.apiOptions.customKeypad){dimensions=KEYPAD_INPUT_DIMENSIONS;}else {dimensions=NORMAL_DIMENSIONS;}const{INPUT_MARGIN,INPUT_HEIGHT,INPUT_WIDTH}=dimensions;const matrixSize=getMatrixSize(this.props.answers);const maxRows=this.props.matrixBoardSize[0];const maxCols=this.props.matrixBoardSize[1];const cursorRow=this.props.cursorPosition[0];const cursorCol=this.props.cursorPosition[1];const highlightedRow=Math.max(cursorRow,matrixSize[0]-1);const highlightedCol=Math.max(cursorCol,matrixSize[1]-1);const bracketHeight=(highlightedRow+1)*(INPUT_HEIGHT+2*INPUT_MARGIN);const bracketOffset=(highlightedCol+1)*(INPUT_WIDTH+2*INPUT_MARGIN);const className=classNames$1({"perseus-matrix":true,"static-mode":this.props.static,"the-matrix":this.state.enterTheMatrix>=5});return jsxRuntimeExports.jsxs("div",{className:className,children:[this.props.prefix&&jsxRuntimeExports.jsx("div",{className:"matrix-prefix",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.prefix,linterContext:this.props.linterContext,strings:this.context.strings})}),jsxRuntimeExports.jsxs("div",{className:"matrix-input",children:[jsxRuntimeExports.jsx("div",{className:"matrix-bracket bracket-left",style:{height:bracketHeight}}),jsxRuntimeExports.jsx("div",{className:"matrix-bracket bracket-right",style:{height:bracketHeight,left:bracketOffset}}),_(maxRows).times(row=>{const rowVals=this.props.answers[row];return jsxRuntimeExports.jsx("div",{className:"matrix-row",children:_(maxCols).times(col=>{const outside=row>highlightedRow||col>highlightedCol;const inputProps={className:outside?"outside":"inside",ref:getRefForPath$1(getInputPath$1(row,col)),value:rowVals?rowVals[col]:null,style:{height:INPUT_HEIGHT,width:INPUT_WIDTH,margin:INPUT_MARGIN},disabled:this.props.apiOptions.readOnly,onFocus:()=>{this.cursorPosition=[row,col];this.props.onChange({cursorPosition:[row,col]},()=>{return false});this._handleFocus(row,col);},onBlur:()=>{if(row===this.cursorPosition[0]&&col===this.cursorPosition[1]){this.props.onChange({cursorPosition:[0,0]},()=>{return false});}this._handleBlur(row,col);},onKeyDown:e=>{this.handleKeyDown(row,col,e);},onChange:(value,cb)=>{this.onValueChange(row,col,value,cb);}};let MatrixInput;if(this.props.apiOptions.customKeypad){const style={margin:INPUT_MARGIN,minWidth:INPUT_WIDTH,minHeight:INPUT_HEIGHT,boxSizing:"border-box",backgroundColor:outside?"#f3f3f3":"#fff"};MatrixInput=jsxRuntimeExports.jsx(SimpleKeypadInput,{...inputProps,style:style,scrollable:true,keypadElement:this.props.keypadElement});}else if(this.props.numericInput){MatrixInput=jsxRuntimeExports.jsx(NumberInput,{...inputProps});}else {const updatedProps={...inputProps,style:StyleSheet.create({input:{...inputProps.style,display:"inline-block",padding:0,backgroundColor:outside?"#f3f3f3":"#fff"}}).input};MatrixInput=jsxRuntimeExports.jsx(TextInput,{...updatedProps});}return jsxRuntimeExports.jsx("span",{className:"matrix-input-field",children:MatrixInput},col)})},row)})]}),this.props.suffix&&jsxRuntimeExports.jsx("div",{className:"matrix-suffix",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.suffix,linterContext:this.props.linterContext,strings:this.context.strings})})]})}constructor(...args){super(...args),this.state={enterTheMatrix:0},this.getInputPaths=()=>{const inputPaths=[];const maxRows=this.props.matrixBoardSize[0];const maxCols=this.props.matrixBoardSize[1];for(let row=0;row<maxRows;row++){for(let col=0;col<maxCols;col++){const inputPath=getInputPath$1(row,col);inputPaths.push(inputPath);}}return inputPaths},this._handleFocus=(row,col)=>{this.props.onFocus(getInputPath$1(row,col));},this._handleBlur=(row,col)=>{this.props.onBlur(getInputPath$1(row,col));},this.focus=()=>{this.focusInputPath(getDefaultPath$1());return true},this.focusInputPath=path=>{const inputID=getRefForPath$1(path);this.refs[inputID].focus();},this.blurInputPath=path=>{if(path.length===0){path=getDefaultPath$1();}const inputID=getRefForPath$1(path);this.refs[inputID].blur();},this.setInputValue=(inputPath,value,callback)=>{const row=getRowFromPath$1(inputPath);const col=getColumnFromPath$1(inputPath);this.onValueChange(row,col,value,callback);},this.handleKeyDown=(row,col,e)=>{const maxRow=this.props.matrixBoardSize[0];const maxCol=this.props.matrixBoardSize[1];let enterTheMatrix=null;const curInput=this.refs[getRefForPath$1(getInputPath$1(row,col))];const curValueString=curInput.getStringValue();const cursorStartPosition=curInput.getSelectionStart();const cursorEndPosition=curInput.getSelectionEnd();let nextPath=null;if(e.key==="ArrowUp"&&row>0){nextPath=getInputPath$1(row-1,col);}else if(e.key==="ArrowDown"&&row+1<maxRow){nextPath=getInputPath$1(row+1,col);}else if(e.key==="ArrowLeft"&&col>0){if(cursorStartPosition===0&&cursorEndPosition===0){nextPath=getInputPath$1(row,col-1);}}else if(e.key==="ArrowRight"&&col+1<maxCol){if(cursorStartPosition===curValueString.length){nextPath=getInputPath$1(row,col+1);}}else if(e.key==="Enter"){enterTheMatrix=this.state.enterTheMatrix+1;}else if(e.key==="Escape"){enterTheMatrix=0;}if(nextPath){e.preventDefault();const input=this.refs[getRefForPath$1(nextPath)];const inputValString=input.getStringValue();const valueLength=inputValString.length*2;input.focus();if(e.key==="ArrowRight"){input.setSelectionRange(0,0);}else {input.setSelectionRange(valueLength,valueLength);}}if(enterTheMatrix!=null){this.setState({enterTheMatrix:enterTheMatrix});}},this.onValueChange=(row,column,value,cb)=>{const answers=this.props.answers.map(answer=>[...answer]);if(!answers[row]){answers[row]=[];}answers[row][column]=value;this.props.onChange({answers},cb);this.props.trackInteraction();};}}Matrix.contextType=PerseusI18nContext;Matrix.defaultProps={matrixBoardSize:[3,3],answers:[[]],prefix:"",suffix:"",cursorPosition:[0,0],apiOptions:ApiOptions.defaults,linterContext:linterContextDefault};function transform(widgetOptions){const rows=widgetOptions.matrixBoardSize[0];const columns=widgetOptions.matrixBoardSize[1];const blankInput=stringArrayOfSize2D({rows,columns});const{matrixBoardSize,prefix,suffix}=widgetOptions;return {matrixBoardSize,prefix,suffix,emptyMatrix:blankInput}}const staticTransform$2=editorProps=>{const widgetProps=_.pick(editorProps,"matrixBoardSize","prefix","suffix");widgetProps.answers=_.map(editorProps.answers,row=>{return _.map(row,cell=>cell!=null?String(cell):"")});return widgetProps};var Matrix$1 = {name:"matrix",displayName:"Matrix",hidden:true,widget:Matrix,transform,staticTransform:staticTransform$2,isLintable:true};
|
|
2042
2029
|
|
|
2043
2030
|
const getPromptJSON$7=()=>{return getUnsupportedPromptJSON("measurer")};
|
|
2044
2031
|
|
|
@@ -2054,11 +2041,11 @@ const{layout}=MoleculeLayout;const parse=SmilesParser.parse;const ParseError=Smi
|
|
|
2054
2041
|
|
|
2055
2042
|
const getPromptJSON$6=(renderProps,userInput)=>{return {type:"number-line",options:{range:renderProps.range,numDivisions:renderProps.numDivisions,snapDivisions:renderProps.snapDivisions},userInput:{numLinePosition:userInput.numLinePosition,numDivisions:userInput.numDivisions}}};
|
|
2056
2043
|
|
|
2057
|
-
const MovablePoint=Graphie.MovablePoint;const Line=Graphie.Line;const{assert: assert$1}=InteractiveUtil;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";const horizontalPadding=30;const reverseRel={ge:"le",gt:"lt",le:"ge",lt:"gt"};const toggleStrictRel={ge:"gt",gt:"ge",le:"lt",lt:"le"};function formatImproper(n,d){if(d===1){return ""+n}return `\\dfrac{${n}}{${d}}`}function formatMixed(n,d){if(n<0){return "-"+formatMixed(-n,d)}const w=Math.floor(n/d);if(w===0){return formatImproper(n,d)}if(n-w*d===0){return ""+w}return w+formatImproper(n-w*d,d)}function formatNonReduced(n,d,base){const factor=Math.floor(base/d);return formatImproper(n*factor,base)}const _label=(graphie,labelStyle,pos,value,base)=>{value=value||pos;if(labelStyle==="decimal"||labelStyle==="decimal ticks"){return graphie.label([pos,-0.53],Math.round(value*100)/100,"center")}if(labelStyle==="improper"){const frac=KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatImproper(frac[0],frac[1]),"below")}if(labelStyle==="mixed"){const frac=KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatMixed(frac[0],frac[1]),"below")}if(labelStyle==="non-reduced"){const frac=KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatNonReduced(frac[0],frac[1],base),"below")}};const TickMarks=Graphie.createSimpleClass((graphie,props)=>{if(!_.isFinite(props.tickStep)||props.tickStep<=0){return []}const results=[];const{range,labelRange,labelStyle,labelTicks,tickStep,numDivisions}=props;const leftLabel=labelRange[0]==null?range[0]:labelRange[0];const rightLabel=labelRange[1]==null?range[1]:labelRange[1];let base;if(labelStyle==="non-reduced"){const fractions=[leftLabel,rightLabel];for(let i=0;i<=numDivisions;i++){const x=range[0]+i*tickStep;fractions.push(x);}const getDenom=x=>number.toFraction(x)[1];const denoms=_.map(fractions,getDenom);base=_.reduce(denoms,(x,y)=>KhanMath.getLCM(x,y));}else {base=undefined;}const highlightedLineStyle={stroke:KhanColors.BLUE,strokeWidth:3.5};const highlightedTextStyle={color:KhanColors.BLUE};const initialTicks=[...Array(Math.round(numDivisions)).keys()].map(index=>range[0]+index*tickStep);const byNumericAscending=(a,b)=>a-b;const allTicks=[...new Set([...initialTicks,leftLabel,rightLabel,...range])].sort(byNumericAscending);allTicks.forEach(tick=>{const tickIsHighlighted=tick===leftLabel||tick===rightLabel;const lineStyle=tickIsHighlighted?highlightedLineStyle:null;const textStyle=tickIsHighlighted?highlightedTextStyle:null;graphie.style(lineStyle,()=>{results.push(graphie.line([tick,-0.2],[tick,.2]));});if(labelTicks||tickIsHighlighted||labelStyle==="decimal ticks"){graphie.style(textStyle,()=>{results.push(_label(graphie,labelStyle,tick,tick,base));});}});return results});class NumberLine extends React.Component{focus(){if(this.props.isTickCtrl){this.refs["tick-ctrl"].focus();return true}return false}getDOMNodeForPath(inputPath){if(inputPath?.length===1){return ReactDOM__default.findDOMNode(this.refs[inputPath[0]])}return null}getUserInput(){return {numLinePosition:this.props.numLinePosition,rel:this.props.isInequality?this.props.rel:"eq",numDivisions:this.props.numDivisions,divisionRange:this.props.divisionRange}}getPromptJSON(){return getPromptJSON$6(this.props,this.getUserInput())}render(){const{strings}=this.context;const divisionRange=this.props.divisionRange;const divRangeString=divisionRange[0]+EN_DASH+divisionRange[1];const invalidNumDivisions=this.props.numDivisions<divisionRange[0]||this.props.numDivisions>divisionRange[1];const inequalityControls=jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:strings.switchDirection,onClick:this.handleReverse}),jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:_(["le","ge"]).contains(this.props.rel)?strings.circleOpen:strings.circleFilled,onClick:this.handleToggleStrict})]});let tickCtrl;if(this.props.isTickCtrl){let Input;if(this.props.apiOptions.customKeypad){Input=SimpleKeypadInput;}else {Input=NumberInput;}tickCtrl=jsxRuntimeExports.jsxs("label",{children:[strings.numDivisions," ",jsxRuntimeExports.jsx(Input,{ref:"tick-ctrl",value:this.state.numDivisionsEmpty?null:this.props.numDivisions||divisionRange[0],checkValidity:val=>val>=divisionRange[0]&&val<=divisionRange[1],onChange:this.onNumDivisionsChange,onFocus:this._handleTickCtrlFocus,onBlur:this._handleTickCtrlBlur,useArrowKeys:true,keypadElement:this.props.keypadElement})]});}return jsxRuntimeExports.jsxs("div",{className:"perseus-widget "+"perseus-widget-interactive-number-line",children:[tickCtrl,!this.isValid()?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:"Invalid number line configuration."}):this.props.isTickCtrl&&invalidNumDivisions?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:strings.divisions({divRangeString:divRangeString})}):this._renderGraphie(),!this.props.static&&this.props.isInequality&&inequalityControls]})}constructor(...args){super(...args),this.state={numDivisionsEmpty:false},this.change=(...args)=>{return change.apply(this,args)},this.isValid=()=>{const range=this.props.range;let initialX=this.props.numLinePosition;const divisionRange=this.props.divisionRange;initialX=initialX==null?range[0]:initialX;return range[0]<range[1]&&number.sign(initialX-range[0])>=0&&number.sign(initialX-range[1])<=0&&divisionRange[0]<divisionRange[1]&&0<this.props.numDivisions&&0<this.props.snapDivisions},this.onNumDivisionsChange=(numDivisions,cb)=>{const divRange=this.props.divisionRange.slice();const width=this.props.range[1]-this.props.range[0];numDivisions=Math.round(numDivisions);numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){const nextProps=_.extend({},this.props,{tickStep:width/numDivisions});const newNumLinePosition=this.snapNumLinePosition(nextProps,this.props.numLinePosition);this.setState({numDivisionsEmpty:false},()=>{this.props.onChange({divisionRange:divRange,numDivisions:numDivisions,numLinePosition:newNumLinePosition},cb);});}else {this.setState({numDivisionsEmpty:true},cb);}},this._handleTickCtrlFocus=()=>{this.props.onFocus(["tick-ctrl"]);},this._handleTickCtrlBlur=()=>{this.props.onBlur(["tick-ctrl"]);},this.focusInputPath=path=>{if(path.length===1){this.refs[path[0]].focus();}},this.blurInputPath=path=>{if(path.length===1){this.refs[path[0]].blur();}},this.getInputPaths=()=>{if(this.props.isTickCtrl){return [["tick-ctrl"]]}return []},this.setInputValue=(inputPath,value,callback)=>{if(inputPath.length===1&&inputPath[0]==="tick-ctrl"){this.onNumDivisionsChange(value,callback);}},this._renderGraphie=()=>{const range=this.props.range;const width=range[1]-range[0];const options=_.pick(this.props,["range","isTickCtrl"]);const props=_.extend({},this.props,{tickStep:width/this.props.numDivisions});return jsxRuntimeExports.jsxs(Graphie,{ref:"graphie",box:[this.props.apiOptions.isMobile?288:460,80],options:options,onMouseDown:coord=>{this.refs.graphie.movables.numberLinePoint.grab(coord);},setup:this._setupGraphie,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable,isMobile:this.props.apiOptions.isMobile,children:[jsxRuntimeExports.jsx(TickMarks,{..._.pick(props,["range","numDivisions","labelTicks","labelStyle","labelRange","tickStep"]),isMobile:this.props.apiOptions.isMobile}),this._renderInequality(props),this._renderNumberLinePoint(props)]},this.props.labelStyle)},this.snapNumLinePosition=(props,numLinePosition)=>{const left=props.range[0];const right=props.range[1];const snapX=props.tickStep/props.snapDivisions;let x=bound(numLinePosition,left,right);x=left+number.roundTo(x-left,snapX);assert$1(_.isFinite(x));return x},this.movePosition=targetPosition=>{this.change({numLinePosition:targetPosition});this.props.trackInteraction();},this._renderNumberLinePoint=props=>{const isOpen=_(["lt","gt"]).contains(props.rel);let fill;if(isOpen){fill=KhanColors._BACKGROUND;}else if(props.static){fill=KhanColors.BLUE;}else {fill=KhanColors.GREEN;}const normalStyle={fill:fill,stroke:props.static?KhanColors.BLUE:KhanColors.GREEN,"stroke-width":isOpen?3:1};const highlightStyle={fill:isOpen?KhanColors._BACKGROUND:KhanColors.GREEN,"stroke-width":isOpen?3:1};const mobileDotStyle=props.isInequality?{stroke:KhanColors.GREEN,"fill-opacity":isOpen?0:1}:{};return jsxRuntimeExports.jsx(MovablePoint,{ref:"numberLinePoint",pointSize:6,coord:[props.numLinePosition,0],constraints:[(coord,prevCoord)=>{return [coord[0],prevCoord[1]]},(coord,prevCoord)=>{const x=this.snapNumLinePosition(props,coord[0]);return [x,coord[1]]}],normalStyle:normalStyle,highlightStyle:highlightStyle,onMove:coord=>{this.movePosition(coord[0]);},isMobile:this.props.apiOptions.isMobile,mobileStyleOverride:mobileDotStyle,showTooltips:this.props.showTooltips,xOnlyTooltip:true})},this.handleReverse=()=>{const newRel=reverseRel[this.props.rel];this.props.onChange({rel:newRel});},this.handleToggleStrict=()=>{const newRel=toggleStrictRel[this.props.rel];this.props.onChange({rel:newRel});},this._getInequalityEndpoint=props=>{const isGreater=_(["ge","gt"]).contains(props.rel);const widthInPixels=400;const range=props.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const end=isGreater?[right,0]:[left,0];return end},this._renderInequality=props=>{if(props.isInequality){const end=this._getInequalityEndpoint(props);const style={arrows:"->",stroke:this.props.apiOptions.isMobile?KhanColors.GREEN:KhanColors.BLUE,strokeWidth:3.5};const isGreater=["ge","gt"].includes(props.rel);return jsxRuntimeExports.jsx(Line,{start:[(isGreater?.4:-0.4)+props.numLinePosition,0],end:end,style:style})}return null},this._setupGraphie=(graphie,options)=>{if(!this.isValid()){return}const widthInPixels=this.props.apiOptions.isMobile?288-horizontalPadding*2:400;const range=options.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const hasFractionalLabels=this.props.labelStyle==="improper"||this.props.labelStyle==="mixed"||this.props.labelStyle==="non-reduced";const bottom=hasFractionalLabels?-1.5:-1;const top=1;graphie.init({range:[[left,right],[bottom,top]],scale:[1/scale,40],isMobile:this.props.apiOptions.isMobile});const center=(range[0]+range[1])/2;graphie.line([center,0],[right,0],{arrows:"->"});graphie.line([center,0],[left,0],{arrows:"->"});};}}NumberLine.contextType=PerseusI18nContext;NumberLine.defaultProps={range:[0,10],labelStyle:"decimal",labelRange:[null,null],divisionRange:[1,12],labelTicks:true,isTickCtrl:false,isInequality:false,numLinePosition:0,snapDivisions:2,showTooltips:false,rel:"ge",apiOptions:ApiOptions.defaults};const numberLineTransform=editorProps=>{const props=_.pick(editorProps,["range","labelRange","labelStyle","labelTicks","divisionRange","snapDivisions","isTickCtrl","isInequality","showTooltips"]);const numLinePosition=editorProps.initialX!=null?editorProps.initialX:editorProps.range[0];const width=editorProps.range[1]-editorProps.range[0];let numDivisions;if(editorProps.numDivisions!=null){numDivisions=editorProps.numDivisions;}else if(editorProps.tickStep!=null){numDivisions=width/editorProps.tickStep;}else {numDivisions=undefined;}_.extend(props,{numLinePosition:numLinePosition,numDivisions:numDivisions,snapDivisions:props.snapDivisions||undefined});return props};const staticTransform$1=editorProps=>{const props=_.pick(editorProps,["range","labelRange","labelStyle","labelTicks","divisionRange","snapDivisions","isInequality"]);const numLinePosition=editorProps.correctX!=null?editorProps.correctX:editorProps.range[0];const width=editorProps.range[1]-editorProps.range[0];let numDivisions;if(editorProps.numDivisions!=null){numDivisions=editorProps.numDivisions;}else if(editorProps.tickStep!=null){numDivisions=width/editorProps.tickStep;}else {numDivisions=undefined;}_.extend(props,{numLinePosition:numLinePosition,numDivisions:numDivisions,rel:editorProps.isInequality?editorProps.correctRel:null,snapDivisions:props.snapDivisions||undefined});return props};var NumberLine$1 = {name:"number-line",displayName:"Number line",widget:NumberLine,transform:numberLineTransform,staticTransform:staticTransform$1};
|
|
2044
|
+
const MovablePoint=Graphie.MovablePoint;const Line=Graphie.Line;const{assert: assert$1}=InteractiveUtil;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";const horizontalPadding=30;const reverseRel={eq:"eq",ge:"le",gt:"lt",le:"ge",lt:"gt"};const toggleStrictRel={eq:"eq",ge:"gt",gt:"ge",le:"lt",lt:"le"};function formatImproper(n,d){if(d===1){return ""+n}return `\\dfrac{${n}}{${d}}`}function formatMixed(n,d){if(n<0){return "-"+formatMixed(-n,d)}const w=Math.floor(n/d);if(w===0){return formatImproper(n,d)}if(n-w*d===0){return ""+w}return w+formatImproper(n-w*d,d)}function formatNonReduced(n,d,base){const factor=Math.floor(base/d);return formatImproper(n*factor,base)}const _label=(graphie,labelStyle,pos,value,base)=>{value=value||pos;if(labelStyle==="decimal"||labelStyle==="decimal ticks"){return graphie.label([pos,-0.53],Math.round(value*100)/100,"center")}if(labelStyle==="improper"){const frac=KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatImproper(frac[0],frac[1]),"below")}if(labelStyle==="mixed"){const frac=KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatMixed(frac[0],frac[1]),"below")}if(labelStyle==="non-reduced"){const frac=KhanMath.toFraction(value);return graphie.label([pos,-0.17],formatNonReduced(frac[0],frac[1],base),"below")}};const TickMarks=Graphie.createSimpleClass((graphie,props)=>{if(!_.isFinite(props.tickStep)||props.tickStep<=0){return []}const results=[];const{range,labelRange,labelStyle,labelTicks,tickStep,numDivisions}=props;const leftLabel=labelRange[0]==null?range[0]:labelRange[0];const rightLabel=labelRange[1]==null?range[1]:labelRange[1];let base;if(labelStyle==="non-reduced"){const fractions=[leftLabel,rightLabel];for(let i=0;i<=numDivisions;i++){const x=range[0]+i*tickStep;fractions.push(x);}const getDenom=x=>number.toFraction(x)[1];const denoms=_.map(fractions,getDenom);base=_.reduce(denoms,(x,y)=>KhanMath.getLCM(x,y));}else {base=undefined;}const highlightedLineStyle={stroke:KhanColors.BLUE,strokeWidth:3.5};const highlightedTextStyle={color:KhanColors.BLUE};const initialTicks=[...Array(Math.round(numDivisions)).keys()].map(index=>range[0]+index*tickStep);const byNumericAscending=(a,b)=>a-b;const allTicks=[...new Set([...initialTicks,leftLabel,rightLabel,...range])].sort(byNumericAscending);allTicks.forEach(tick=>{const tickIsHighlighted=tick===leftLabel||tick===rightLabel;const lineStyle=tickIsHighlighted?highlightedLineStyle:null;const textStyle=tickIsHighlighted?highlightedTextStyle:null;graphie.style(lineStyle,()=>{results.push(graphie.line([tick,-0.2],[tick,.2]));});if(labelTicks||tickIsHighlighted||labelStyle==="decimal ticks"){graphie.style(textStyle,()=>{results.push(_label(graphie,labelStyle,tick,tick,base));});}});return results});class NumberLine extends React.Component{focus(){if(this.props.isTickCtrl){this.refs["tick-ctrl"].focus();return true}return false}getDOMNodeForPath(inputPath){if(inputPath?.length===1){return ReactDOM__default.findDOMNode(this.refs[inputPath[0]])}return null}getUserInput(){return {numLinePosition:this.props.numLinePosition,rel:this.props.isInequality?this.props.rel:"eq",numDivisions:this.props.numDivisions,divisionRange:this.props.divisionRange}}getPromptJSON(){return getPromptJSON$6(this.props,this.getUserInput())}render(){const{strings}=this.context;const divisionRange=this.props.divisionRange;const divRangeString=divisionRange[0]+EN_DASH+divisionRange[1];const invalidNumDivisions=this.props.numDivisions<divisionRange[0]||this.props.numDivisions>divisionRange[1];const inequalityControls=jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:strings.switchDirection,onClick:this.handleReverse}),jsxRuntimeExports.jsx("input",{type:"button",className:"simple-button",value:_(["le","ge"]).contains(this.props.rel)?strings.circleOpen:strings.circleFilled,onClick:this.handleToggleStrict})]});let tickCtrl;if(this.props.isTickCtrl){let Input;if(this.props.apiOptions.customKeypad){Input=SimpleKeypadInput;}else {Input=NumberInput;}tickCtrl=jsxRuntimeExports.jsxs("label",{children:[strings.numDivisions," ",jsxRuntimeExports.jsx(Input,{ref:"tick-ctrl",value:this.state.numDivisionsEmpty?null:this.props.numDivisions||divisionRange[0],checkValidity:val=>val>=divisionRange[0]&&val<=divisionRange[1],onChange:this.onNumDivisionsChange,onFocus:this._handleTickCtrlFocus,onBlur:this._handleTickCtrlBlur,useArrowKeys:true,keypadElement:this.props.keypadElement})]});}return jsxRuntimeExports.jsxs("div",{className:"perseus-widget "+"perseus-widget-interactive-number-line",children:[tickCtrl,!this.isValid()?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:"Invalid number line configuration."}):this.props.isTickCtrl&&invalidNumDivisions?jsxRuntimeExports.jsx("div",{className:"perseus-error",children:strings.divisions({divRangeString:divRangeString})}):this._renderGraphie(),!this.props.static&&this.props.isInequality&&inequalityControls]})}constructor(...args){super(...args),this.state={numDivisionsEmpty:false},this.change=(...args)=>{return change.apply(this,args)},this.isValid=()=>{const range=this.props.range;let initialX=this.props.numLinePosition;const divisionRange=this.props.divisionRange;initialX=initialX==null?range[0]:initialX;return range[0]<range[1]&&number.sign(initialX-range[0])>=0&&number.sign(initialX-range[1])<=0&&divisionRange[0]<divisionRange[1]&&0<this.props.numDivisions&&0<this.props.snapDivisions},this.onNumDivisionsChange=(numDivisions,cb)=>{const divRange=this.props.divisionRange.slice();const width=this.props.range[1]-this.props.range[0];numDivisions=Math.round(numDivisions);numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){const nextProps=_.extend({},this.props,{tickStep:width/numDivisions});const newNumLinePosition=this.snapNumLinePosition(nextProps,this.props.numLinePosition);this.setState({numDivisionsEmpty:false},()=>{this.props.onChange({divisionRange:divRange,numDivisions:numDivisions,numLinePosition:newNumLinePosition},cb);});}else {this.setState({numDivisionsEmpty:true},cb);}},this._handleTickCtrlFocus=()=>{this.props.onFocus(["tick-ctrl"]);},this._handleTickCtrlBlur=()=>{this.props.onBlur(["tick-ctrl"]);},this.focusInputPath=path=>{if(path.length===1){this.refs[path[0]].focus();}},this.blurInputPath=path=>{if(path.length===1){this.refs[path[0]].blur();}},this.getInputPaths=()=>{if(this.props.isTickCtrl){return [["tick-ctrl"]]}return []},this.setInputValue=(inputPath,value,callback)=>{if(inputPath.length===1&&inputPath[0]==="tick-ctrl"){this.onNumDivisionsChange(value,callback);}},this._renderGraphie=()=>{const range=this.props.range;const width=range[1]-range[0];const options=_.pick(this.props,["range","isTickCtrl"]);const props=_.extend({},this.props,{tickStep:width/this.props.numDivisions});return jsxRuntimeExports.jsxs(Graphie,{ref:"graphie",box:[this.props.apiOptions.isMobile?288:460,80],options:options,onMouseDown:coord=>{this.refs.graphie.movables.numberLinePoint.grab(coord);},setup:this._setupGraphie,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable,isMobile:this.props.apiOptions.isMobile,children:[jsxRuntimeExports.jsx(TickMarks,{..._.pick(props,["range","numDivisions","labelTicks","labelStyle","labelRange","tickStep"]),isMobile:this.props.apiOptions.isMobile}),this._renderInequality(props),this._renderNumberLinePoint(props)]},this.props.labelStyle)},this.snapNumLinePosition=(props,numLinePosition)=>{const left=props.range[0];const right=props.range[1];const snapX=props.tickStep/props.snapDivisions;let x=bound(numLinePosition,left,right);x=left+number.roundTo(x-left,snapX);assert$1(_.isFinite(x));return x},this.movePosition=targetPosition=>{this.change({numLinePosition:targetPosition});this.props.trackInteraction();},this._renderNumberLinePoint=props=>{const isOpen=_(["lt","gt"]).contains(props.rel);let fill;if(isOpen){fill=KhanColors._BACKGROUND;}else if(props.static){fill=KhanColors.BLUE;}else {fill=KhanColors.GREEN;}const normalStyle={fill:fill,stroke:props.static?KhanColors.BLUE:KhanColors.GREEN,"stroke-width":isOpen?3:1};const highlightStyle={fill:isOpen?KhanColors._BACKGROUND:KhanColors.GREEN,"stroke-width":isOpen?3:1};const mobileDotStyle=props.isInequality?{stroke:KhanColors.GREEN,"fill-opacity":isOpen?0:1}:{};return jsxRuntimeExports.jsx(MovablePoint,{ref:"numberLinePoint",pointSize:6,coord:[props.numLinePosition,0],constraints:[(coord,prevCoord)=>{return [coord[0],prevCoord[1]]},(coord,prevCoord)=>{const x=this.snapNumLinePosition(props,coord[0]);return [x,coord[1]]}],normalStyle:normalStyle,highlightStyle:highlightStyle,onMove:coord=>{this.movePosition(coord[0]);},isMobile:this.props.apiOptions.isMobile,mobileStyleOverride:mobileDotStyle,showTooltips:this.props.showTooltips,xOnlyTooltip:true})},this.handleReverse=()=>{const newRel=reverseRel[this.props.rel];this.props.onChange({rel:newRel});},this.handleToggleStrict=()=>{const newRel=toggleStrictRel[this.props.rel];this.props.onChange({rel:newRel});},this._getInequalityEndpoint=props=>{const isGreater=_(["ge","gt"]).contains(props.rel);const widthInPixels=400;const range=props.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const end=isGreater?[right,0]:[left,0];return end},this._renderInequality=props=>{if(props.isInequality){const end=this._getInequalityEndpoint(props);const style={arrows:"->",stroke:this.props.apiOptions.isMobile?KhanColors.GREEN:KhanColors.BLUE,strokeWidth:3.5};const isGreater=["ge","gt"].includes(props.rel);return jsxRuntimeExports.jsx(Line,{start:[(isGreater?.4:-0.4)+props.numLinePosition,0],end:end,style:style})}return null},this._setupGraphie=(graphie,options)=>{if(!this.isValid()){return}const widthInPixels=this.props.apiOptions.isMobile?288-horizontalPadding*2:400;const range=options.range;const scale=(range[1]-range[0])/widthInPixels;const buffer=horizontalPadding*scale;const left=range[0]-buffer;const right=range[1]+buffer;const hasFractionalLabels=this.props.labelStyle==="improper"||this.props.labelStyle==="mixed"||this.props.labelStyle==="non-reduced";const bottom=hasFractionalLabels?-1.5:-1;const top=1;graphie.init({range:[[left,right],[bottom,top]],scale:[1/scale,40],isMobile:this.props.apiOptions.isMobile});const center=(range[0]+range[1])/2;graphie.line([center,0],[right,0],{arrows:"->"});graphie.line([center,0],[left,0],{arrows:"->"});};}}NumberLine.contextType=PerseusI18nContext;NumberLine.defaultProps={range:[0,10],labelStyle:"decimal",labelRange:[null,null],divisionRange:[1,12],labelTicks:true,isTickCtrl:false,isInequality:false,numLinePosition:0,snapDivisions:2,showTooltips:false,rel:"ge",apiOptions:ApiOptions.defaults};function numberLineTransform(editorProps){const props=_.pick(editorProps,["range","labelRange","labelStyle","labelTicks","divisionRange","snapDivisions","isTickCtrl","isInequality","showTooltips"]);const numLinePosition=editorProps.initialX!=null?editorProps.initialX:editorProps.range[0];const width=editorProps.range[1]-editorProps.range[0];let numDivisions;if(editorProps.numDivisions!=null){numDivisions=editorProps.numDivisions;}else if(editorProps.tickStep!=null){numDivisions=width/editorProps.tickStep;}else {numDivisions=undefined;}return {...props,isTickCtrl:editorProps.isTickCtrl??undefined,numLinePosition:numLinePosition,numDivisions:numDivisions,snapDivisions:props.snapDivisions||undefined}}function staticTransform$1(editorProps){const props=_.pick(editorProps,["range","labelRange","labelStyle","labelTicks","divisionRange","snapDivisions","isInequality"]);const numLinePosition=editorProps.correctX!=null?editorProps.correctX:editorProps.range[0];const width=editorProps.range[1]-editorProps.range[0];let numDivisions;if(editorProps.numDivisions!=null){numDivisions=editorProps.numDivisions;}else if(editorProps.tickStep!=null){numDivisions=width/editorProps.tickStep;}else {numDivisions=undefined;}return {...props,numLinePosition:numLinePosition,numDivisions:numDivisions,rel:editorProps.isInequality?editorProps.correctRel:undefined,snapDivisions:props.snapDivisions||undefined}}var NumberLine$1 = {name:"number-line",displayName:"Number line",widget:NumberLine,transform:numberLineTransform,staticTransform:staticTransform$1};
|
|
2058
2045
|
|
|
2059
2046
|
const getPromptJSON$5=(renderProps,userInput)=>{return {type:"orderer",options:{options:renderProps.options.map(option=>option.content)},userInput:{values:userInput.current}}};
|
|
2060
2047
|
|
|
2061
|
-
class PlaceholderCard extends React.Component{render(){return jsxRuntimeExports.jsx("div",{className:"card-wrap",style:{width:this.props.width},children:jsxRuntimeExports.jsx("div",{className:"card placeholder",style:{height:this.props.width}})})}}class DragHintCard extends React.Component{render(){return jsxRuntimeExports.jsx("div",{className:"card-wrap",children:jsxRuntimeExports.jsx("div",{className:"card drag-hint"})})}}class Card extends React.Component{componentDidMount(){this.mouseMoveUpBound=false;document.addEventListener("touchmove",this.onMouseMove,Util.supportsPassiveEvents()?{passive:false}:false);}shouldComponentUpdate(nextProps,nextState){return this.props.floating||nextProps.floating||this.props.content!==nextProps.content||this.props.fakeRef!==nextProps.fakeRef}componentDidUpdate(prevProps,prevState){if(this.props.animating&&!prevProps.animating&&this.props.animateTo&&this.props.startOffset){const ms=15*Math.sqrt(Math.sqrt(Math.pow(this.props.animateTo.left-this.props.startOffset.left,2)+Math.pow(this.props.animateTo.top-this.props.startOffset.top,2)));$(ReactDOM__default.findDOMNode(this)).animate(this.props.animateTo,Math.max(ms,1),this.props.onAnimationEnd);}}componentWillUnmount(){if(this.mouseMoveUpBound){Log.error("Removing an element with bound event handlers.",Errors.Internal);this.unbindMouseMoveUp();Util.resetTouchHandlers();}document.removeEventListener("touchmove",this.onMouseMove);}render(){let style={};if(this.props.floating){style={position:"absolute",left:this.props.startOffset?.left,top:this.props.startOffset?.top};}if(this.props.width){style.width=this.props.width;}const className=["card"];if(this.props.stack){className.push("stack");}if(this.props.floating&&!this.props.animating&&this.props.mouse&&this.props.startMouse){className.push("dragging");style.left+=this.props.mouse.left-this.props.startMouse.left;style.top+=this.props.mouse.top-this.props.startMouse.top;}const rendererProps=_.pick(this.props,"content");const onMouseDown=this.props.animating?$.noop:this.onMouseDown;return jsxRuntimeExports.jsx("div",{className:"card-wrap",style:style,onMouseDown:onMouseDown,onTouchStart:onMouseDown,onTouchEnd:this.onMouseUp,onTouchCancel:this.onMouseUp,children:jsxRuntimeExports.jsx("div",{className:className.join(" "),children:jsxRuntimeExports.jsx(Renderer,{...rendererProps,linterContext:this.props.linterContext,strings:this.context.strings})})})}constructor(...args){super(...args),this.state={dragging:false},this.bindMouseMoveUp=()=>{this.mouseMoveUpBound=true;$(document).on("mousemove",this.onMouseMove);$(document).on("mouseup",this.onMouseUp);},this.unbindMouseMoveUp=()=>{this.mouseMoveUpBound=false;$(document).off("mousemove",this.onMouseMove);$(document).off("mouseup",this.onMouseUp);},this.onMouseDown=event=>{event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.setState({dragging:true});this.bindMouseMoveUp();this.props.onMouseDown?.(loc,this);}},this.onMouseMove=event=>{if(!this.state.dragging){return}event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.props.onMouseMove?.(loc);}},this.onMouseUp=event=>{event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.setState({dragging:false});this.unbindMouseMoveUp();this.props.onMouseUp?.(loc);}};}}Card.contextType=PerseusI18nContext;Card.defaultProps={stack:false,animating:false,linterContext:linterContextDefault};class Orderer extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.current,nextProps.current)){this.setState({current:nextProps.current});}}getUserInput(){return {current:_.map(this.props.current,function(v){return v.content})}}getPromptJSON(){return getPromptJSON$5(this.props,this.getUserInput())}render(){const dragging=this.state.dragging&&jsxRuntimeExports.jsx(Card,{ref:"dragging",floating:true,content:this.state.dragContent,startOffset:this.state.offsetPos,startMouse:this.state.grabPos,mouse:this.state.mousePos,width:this.state.dragWidth,onMouseUp:this.onRelease,onMouseMove:this.onMouseMove,linterContext:this.props.linterContext},this.state.dragKey||"draggingCard");const animating=this.state.animating&&jsxRuntimeExports.jsx(Card,{floating:true,animating:true,content:this.state.dragContent,startOffset:this.state.offsetPos,width:this.state.dragWidth,animateTo:this.state.animateTo,onAnimationEnd:this.state.onAnimationEnd,linterContext:this.props.linterContext},this.state.dragKey||"draggingCard");const sortableCards=_.map(this.state.current,function(opt,i){return jsxRuntimeExports.jsx(Card,{ref:"sortable"+i,fakeRef:"sortable"+i,floating:false,content:opt.content,width:opt.width,linterContext:this.props.linterContext,onMouseDown:this.state.animating?$.noop:this.onClick.bind(null,"current",i)},`sortableCard${i}`)},this);if(this.state.placeholderIndex!=null){const placeholder=jsxRuntimeExports.jsx(PlaceholderCard,{ref:"placeholder",width:this.state.dragWidth,height:this.state.dragHeight},"placeholder");sortableCards.splice(this.state.placeholderIndex,0,placeholder);}const anySortableCards=sortableCards.length>0;sortableCards.push(dragging,animating);const sortable=jsxRuntimeExports.jsxs("div",{className:"perseus-clearfix draggable-box",children:[!anySortableCards&&jsxRuntimeExports.jsx(DragHintCard,{}),jsxRuntimeExports.jsx("div",{ref:"dragList",children:sortableCards})]});const bank=jsxRuntimeExports.jsx("div",{ref:"bank",className:"bank perseus-clearfix",children:_.map(this.props.options,(opt,i)=>{return jsxRuntimeExports.jsx(Card,{ref:"bank"+i,floating:false,content:opt.content,stack:true,linterContext:this.props.linterContext,onMouseDown:this.state.animating?$.noop:this.onClick.bind(null,"bank",i),onMouseMove:this.onMouseMove,onMouseUp:this.onRelease},i)},this)});return jsxRuntimeExports.jsxs("div",{className:"draggy-boxy-thing orderer "+"height-"+this.props.height+" "+"layout-"+this.props.layout+" "+"blank-background "+"perseus-clearfix ",ref:"orderer",children:[bank,sortable]})}constructor(...args){super(...args),this.state={current:[],dragging:false,placeholderIndex:null,dragKey:null,animating:false,dragContent:null,dragWidth:null,dragHeight:null,offsetPos:null,animateTo:null,grabPos:null},this.onClick=(type,index,loc,draggable)=>{const $draggable=$(ReactDOM__default.findDOMNode(draggable));const list=this.state.current.slice();let opt;let placeholderIndex=null;if(type==="current"){list.splice(index,1);opt=this.state.current[index];placeholderIndex=index;}else if(type==="bank"){opt=this.props.options[index];}this.setState({current:list,dragging:true,placeholderIndex:placeholderIndex,dragKey:opt.key,dragContent:opt.content,dragWidth:$draggable.width(),dragHeight:$draggable.height(),grabPos:loc,mousePos:loc,offsetPos:$draggable.position()});},this.onRelease=loc=>{const draggable=this.refs.dragging;if(draggable==null){return}const inCardBank=this.isCardInBank(draggable);const index=this.state.placeholderIndex||0;const onAnimationEnd=()=>{const list=this.state.current.slice();if(!inCardBank){const newCard={content:this.state.dragContent,key:_.uniqueId("perseus_draggable_card_"),width:this.state.dragWidth};list.splice(index,0,newCard);}this.props.onChange({current:list});this.setState({current:list,dragging:false,placeholderIndex:null,animating:false});this.props.trackInteraction();};const offset=$(ReactDOM__default.findDOMNode(draggable)).position();let finalOffset=null;if(inCardBank){_.each(this.props.options,function(opt,i){if(opt.content===this.state.dragContent){const card=ReactDOM__default.findDOMNode(this.refs["bank"+i]);finalOffset=$(card).position();}},this);}else if(this.refs.placeholder!=null){finalOffset=$(ReactDOM__default.findDOMNode(this.refs.placeholder)).position();}if(finalOffset==null){onAnimationEnd();}else {this.setState({offsetPos:offset,animateTo:finalOffset,onAnimationEnd:onAnimationEnd,animating:true,dragging:false});}},this.onMouseMove=loc=>{const draggable=this.refs.dragging;if(draggable==null){return}let index;if(this.isCardInBank(draggable)){index=null;}else {index=this.findCorrectIndex(draggable,this.state.current);}this.setState({mousePos:loc,placeholderIndex:index});},this.findCorrectIndex=(draggable,list)=>{const isHorizontal=this.props.layout==="horizontal";const $dragList=$(ReactDOM__default.findDOMNode(this.refs.dragList));const leftEdge=$dragList.offset().left;const topEdge=$dragList.offset().top;const midWidth=$(ReactDOM__default.findDOMNode(draggable)).offset().left-leftEdge;const midHeight=$(ReactDOM__default.findDOMNode(draggable)).offset().top-topEdge;let index=0;let sumWidth=0;let sumHeight=0;if(isHorizontal){_.each(list,function(opt,i){const card=ReactDOM__default.findDOMNode(this.refs["sortable"+i]);const outerWidth=$(card).outerWidth(true);if(midWidth>sumWidth+outerWidth/2){index+=1;}sumWidth+=outerWidth;},this);}else {_.each(list,function(opt,i){const card=ReactDOM__default.findDOMNode(this.refs["sortable"+i]);const outerHeight=$(card).outerHeight(true);if(midHeight>sumHeight+outerHeight/2){index+=1;}sumHeight+=outerHeight;},this);}return index},this.isCardInBank=draggable=>{if(draggable==null){return false}const isHorizontal=this.props.layout==="horizontal";const $draggable=$(ReactDOM__default.findDOMNode(draggable));const $bank=$(ReactDOM__default.findDOMNode(this.refs.bank));const draggableOffset=$draggable.offset();const bankOffset=$bank.offset();const draggableHeight=$draggable.outerHeight(true);const bankHeight=$bank.outerHeight(true);const bankWidth=$bank.outerWidth(true);const draggableWidth=$draggable.outerWidth(true);if(isHorizontal){return draggableOffset.top+draggableHeight/2<bankOffset.top+bankHeight}return draggableOffset.left+draggableWidth/2<bankOffset.left+bankWidth},this.setListValues=values=>{const list=values.map(value=>{return {content:value}});this.props.onChange({current:list});this.setState({current:list});};}}Orderer.defaultProps={current:[],options:[],correctOptions:[],height:"normal",layout:"horizontal",linterContext:linterContextDefault};var Orderer$1 = {name:"orderer",displayName:"Orderer",hidden:true,widget:Orderer,isLintable:true};
|
|
2048
|
+
class PlaceholderCard extends React.Component{render(){return jsxRuntimeExports.jsx("div",{className:"card-wrap",style:{width:this.props.width},children:jsxRuntimeExports.jsx("div",{className:"card placeholder",style:{height:this.props.width}})})}}class DragHintCard extends React.Component{render(){return jsxRuntimeExports.jsx("div",{className:"card-wrap",children:jsxRuntimeExports.jsx("div",{className:"card drag-hint"})})}}class Card extends React.Component{componentDidMount(){this.mouseMoveUpBound=false;document.addEventListener("touchmove",this.onMouseMove,Util.supportsPassiveEvents()?{passive:false}:false);}shouldComponentUpdate(nextProps,nextState){return this.props.floating||nextProps.floating||this.props.content!==nextProps.content||this.props.fakeRef!==nextProps.fakeRef}componentDidUpdate(prevProps,prevState){if(this.props.animating&&!prevProps.animating&&this.props.animateTo&&this.props.startOffset){const ms=15*Math.sqrt(Math.sqrt(Math.pow(this.props.animateTo.left-this.props.startOffset.left,2)+Math.pow(this.props.animateTo.top-this.props.startOffset.top,2)));$(ReactDOM__default.findDOMNode(this)).animate(this.props.animateTo,Math.max(ms,1),this.props.onAnimationEnd);}}componentWillUnmount(){if(this.mouseMoveUpBound){Log.error("Removing an element with bound event handlers.",Errors.Internal);this.unbindMouseMoveUp();Util.resetTouchHandlers();}document.removeEventListener("touchmove",this.onMouseMove);}render(){let style={};if(this.props.floating){style={position:"absolute",left:this.props.startOffset?.left,top:this.props.startOffset?.top};}if(this.props.width){style.width=this.props.width;}const className=["card"];if(this.props.stack){className.push("stack");}if(this.props.floating&&!this.props.animating&&this.props.mouse&&this.props.startMouse){className.push("dragging");style.left+=this.props.mouse.left-this.props.startMouse.left;style.top+=this.props.mouse.top-this.props.startMouse.top;}const rendererProps={content:this.props.content};const onMouseDown=this.props.animating?$.noop:this.onMouseDown;return jsxRuntimeExports.jsx("div",{className:"card-wrap",style:style,onMouseDown:onMouseDown,onTouchStart:onMouseDown,onTouchEnd:this.onMouseUp,onTouchCancel:this.onMouseUp,children:jsxRuntimeExports.jsx("div",{className:className.join(" "),children:jsxRuntimeExports.jsx(Renderer,{...rendererProps,linterContext:this.props.linterContext,strings:this.context.strings})})})}constructor(...args){super(...args),this.state={dragging:false},this.bindMouseMoveUp=()=>{this.mouseMoveUpBound=true;$(document).on("mousemove",this.onMouseMove);$(document).on("mouseup",this.onMouseUp);},this.unbindMouseMoveUp=()=>{this.mouseMoveUpBound=false;$(document).off("mousemove",this.onMouseMove);$(document).off("mouseup",this.onMouseUp);},this.onMouseDown=event=>{event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.setState({dragging:true});this.bindMouseMoveUp();this.props.onMouseDown?.(loc,this);}},this.onMouseMove=event=>{if(!this.state.dragging){return}event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.props.onMouseMove?.(loc);}},this.onMouseUp=event=>{event.preventDefault();const loc=Util.extractPointerLocation(event);if(loc){this.setState({dragging:false});this.unbindMouseMoveUp();this.props.onMouseUp?.(loc);}};}}Card.contextType=PerseusI18nContext;Card.defaultProps={stack:false,animating:false,linterContext:linterContextDefault};class Orderer extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.current,nextProps.current)){this.setState({current:nextProps.current});}}getUserInput(){return {current:this.props.current.map(function(v){return v.content})}}getPromptJSON(){return getPromptJSON$5(this.props,this.getUserInput())}render(){const dragging=this.state.dragging&&jsxRuntimeExports.jsx(Card,{ref:"dragging",floating:true,content:this.state.dragContent,startOffset:this.state.offsetPos,startMouse:this.state.grabPos,mouse:this.state.mousePos,width:this.state.dragWidth,onMouseUp:this.onRelease,onMouseMove:this.onMouseMove,linterContext:this.props.linterContext},this.state.dragKey||"draggingCard");const animating=this.state.animating&&jsxRuntimeExports.jsx(Card,{floating:true,animating:true,content:this.state.dragContent,startOffset:this.state.offsetPos,width:this.state.dragWidth,animateTo:this.state.animateTo,onAnimationEnd:this.state.onAnimationEnd,linterContext:this.props.linterContext},this.state.dragKey||"draggingCard");const sortableCards=this.state.current.map((opt,i)=>{return jsxRuntimeExports.jsx(Card,{ref:"sortable"+i,fakeRef:"sortable"+i,floating:false,content:opt.content,width:opt.width,linterContext:this.props.linterContext,onMouseDown:this.state.animating?$.noop:this.onClick.bind(null,"current",i)},`sortableCard${i}`)});if(this.state.placeholderIndex!=null){const placeholder=jsxRuntimeExports.jsx(PlaceholderCard,{ref:"placeholder",width:this.state.dragWidth,height:this.state.dragHeight},"placeholder");sortableCards.splice(this.state.placeholderIndex,0,placeholder);}const anySortableCards=sortableCards.length>0;sortableCards.push(dragging,animating);const sortable=jsxRuntimeExports.jsxs("div",{className:"perseus-clearfix draggable-box",children:[!anySortableCards&&jsxRuntimeExports.jsx(DragHintCard,{}),jsxRuntimeExports.jsx("div",{ref:"dragList",children:sortableCards})]});const bank=jsxRuntimeExports.jsx("div",{ref:"bank",className:"bank perseus-clearfix",children:this.props.options.map((opt,i)=>{return jsxRuntimeExports.jsx(Card,{ref:"bank"+i,floating:false,content:opt.content,stack:true,linterContext:this.props.linterContext,onMouseDown:this.state.animating?$.noop:this.onClick.bind(null,"bank",i),onMouseMove:this.onMouseMove,onMouseUp:this.onRelease},i)})});return jsxRuntimeExports.jsxs("div",{className:"draggy-boxy-thing orderer "+"height-"+this.props.height+" "+"layout-"+this.props.layout+" "+"blank-background "+"perseus-clearfix ",ref:"orderer",children:[bank,sortable]})}constructor(...args){super(...args),this.state={current:[],dragging:false,placeholderIndex:null,dragKey:null,animating:false,dragContent:null,dragWidth:null,dragHeight:null,offsetPos:null,animateTo:null,grabPos:null},this.onClick=(type,index,loc,draggable)=>{const $draggable=$(ReactDOM__default.findDOMNode(draggable));const list=this.state.current.slice();let opt;let placeholderIndex=null;if(type==="current"){list.splice(index,1);opt=this.state.current[index];placeholderIndex=index;}else if(type==="bank"){opt=this.props.options[index];}this.setState({current:list,dragging:true,placeholderIndex:placeholderIndex,dragKey:opt.key,dragContent:opt.content,dragWidth:$draggable.width(),dragHeight:$draggable.height(),grabPos:loc,mousePos:loc,offsetPos:$draggable.position()});},this.onRelease=loc=>{const draggable=this.refs.dragging;if(draggable==null){return}const inCardBank=this.isCardInBank(draggable);const index=this.state.placeholderIndex||0;const onAnimationEnd=()=>{const list=this.state.current.slice();if(!inCardBank){const newCard={content:this.state.dragContent,key:_.uniqueId("perseus_draggable_card_"),width:this.state.dragWidth};list.splice(index,0,newCard);}this.props.onChange({current:list});this.setState({current:list,dragging:false,placeholderIndex:null,animating:false});this.props.trackInteraction();};const offset=$(ReactDOM__default.findDOMNode(draggable)).position();let finalOffset=null;if(inCardBank){this.props.options.forEach((opt,i)=>{if(opt.content===this.state.dragContent){const card=ReactDOM__default.findDOMNode(this.refs["bank"+i]);finalOffset=$(card).position();}});}else if(this.refs.placeholder!=null){finalOffset=$(ReactDOM__default.findDOMNode(this.refs.placeholder)).position();}if(finalOffset==null){onAnimationEnd();}else {this.setState({offsetPos:offset,animateTo:finalOffset,onAnimationEnd:onAnimationEnd,animating:true,dragging:false});}},this.onMouseMove=loc=>{const draggable=this.refs.dragging;if(draggable==null){return}let index;if(this.isCardInBank(draggable)){index=null;}else {index=this.findCorrectIndex(draggable,this.state.current);}this.setState({mousePos:loc,placeholderIndex:index});},this.findCorrectIndex=(draggable,list)=>{const isHorizontal=this.props.layout==="horizontal";const $dragList=$(ReactDOM__default.findDOMNode(this.refs.dragList));const leftEdge=$dragList.offset().left;const topEdge=$dragList.offset().top;const midWidth=$(ReactDOM__default.findDOMNode(draggable)).offset().left-leftEdge;const midHeight=$(ReactDOM__default.findDOMNode(draggable)).offset().top-topEdge;let index=0;let sumWidth=0;let sumHeight=0;if(isHorizontal){list.forEach((opt,i)=>{const card=ReactDOM__default.findDOMNode(this.refs["sortable"+i]);const outerWidth=$(card).outerWidth(true);if(midWidth>sumWidth+outerWidth/2){index+=1;}sumWidth+=outerWidth;});}else {list.forEach((_,i)=>{const card=ReactDOM__default.findDOMNode(this.refs["sortable"+i]);const outerHeight=$(card).outerHeight(true);if(midHeight>sumHeight+outerHeight/2){index+=1;}sumHeight+=outerHeight;});}return index},this.isCardInBank=draggable=>{if(draggable==null){return false}const isHorizontal=this.props.layout==="horizontal";const $draggable=$(ReactDOM__default.findDOMNode(draggable));const $bank=$(ReactDOM__default.findDOMNode(this.refs.bank));const draggableOffset=$draggable.offset();const bankOffset=$bank.offset();const draggableHeight=$draggable.outerHeight(true);const bankHeight=$bank.outerHeight(true);const bankWidth=$bank.outerWidth(true);const draggableWidth=$draggable.outerWidth(true);if(isHorizontal){return draggableOffset.top+draggableHeight/2<bankOffset.top+bankHeight}return draggableOffset.left+draggableWidth/2<bankOffset.left+bankWidth},this.setListValues=values=>{const list=values.map(value=>{return {content:value}});this.props.onChange({current:list});this.setState({current:list});};}}Orderer.defaultProps={current:[],options:[],height:"normal",layout:"horizontal",linterContext:linterContextDefault};var Orderer$1 = {name:"orderer",displayName:"Orderer",hidden:true,widget:Orderer,isLintable:true};
|
|
2062
2049
|
|
|
2063
2050
|
class PassageRefTarget extends React.Component{render(){return jsxRuntimeExports.jsx(Renderer,{content:this.props.content,apiOptions:this.props.apiOptions,linterContext:this.props.linterContext,strings:this.context.strings})}constructor(...args){super(...args),this.isWidget=true,this.change=(...args)=>{return change.apply(this,args)};}}PassageRefTarget.contextType=PerseusI18nContext;PassageRefTarget.defaultProps={content:"",linterContext:linterContextDefault};var PassageRefTarget$1 = {name:"passage-ref-target",displayName:"PassageRefTarget",widget:PassageRefTarget,hidden:true,transform:editorProps=>{return _.pick(editorProps,"content")},isLintable:true};
|
|
2064
2051
|
|
|
@@ -2088,9 +2075,9 @@ const DEFAULT_WIDTH=1280;const DEFAULT_HEIGHT=720;const KA_EMBED="{host}/embed_v
|
|
|
2088
2075
|
|
|
2089
2076
|
var extraWidgets = [Categorizer$1,CSProgram$1,Dropdown$1,Explanation$1,Definition$1,Grapher$1,GradedGroup$1,GradedGroupSet$1,Group$1,Iframe$1,Image$1,Interactive,InteractiveGraph$1,LabelImage$1,Matrix$1,Matcher$1,Measurer$1,Molecule$1,NumberLine$1,Orderer$1,Passage$1,PassageRef$1,PassageRefTarget$1,PhetSimulation$1,Plotter$1,PythonProgram$1,Sorter$1,Table$1,Video$1,DeprecatedStandin$1];
|
|
2090
2077
|
|
|
2091
|
-
const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
|
|
2078
|
+
const init=function(){registerCoreWidgets();registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
|
|
2092
2079
|
|
|
2093
|
-
const libName="@khanacademy/perseus";const libVersion="61.0
|
|
2080
|
+
const libName="@khanacademy/perseus";const libVersion="61.1.0";addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
2094
2081
|
|
|
2095
2082
|
const apiVersion={major:12,minor:0};
|
|
2096
2083
|
|
|
@@ -2118,7 +2105,7 @@ function traverseRenderer(itemData,widgets){traverse(itemData,null,function(info
|
|
|
2118
2105
|
|
|
2119
2106
|
function displaySigFigs(f,sigFigs,sigDecs,scientific){const s=""+f;let order=parseOrder(s);let mantissa=parseMantissa(s);let positive=parseSign(s);let add;let decAdd;let sigAdd;let zeroScientific=false;if(f==0||mantissa==""||mantissa=="0"){mantissa="";for(let i=0;i<sigFigs;i++){mantissa+="0";}order=sigFigs+sigDecs;if(sigDecs<0&&-sigDecs>=sigFigs){zeroScientific=true;}}else {decAdd=order-mantissa.length-sigDecs;sigAdd=sigFigs-mantissa.length;add=Math.min(sigAdd,decAdd);if(add<0){let rounded=round(mantissa,-add);if(rounded.length>mantissa.length+add){order++;if(decAdd>sigAdd){rounded=round(rounded,1);}}mantissa=rounded;}else if(add>0){for(let i=0;i<add;i++){mantissa+="0";}}if(mantissa==""||mantissa=="0"){mantissa="0";positive=true;order=1+sigDecs;if(order!=0){zeroScientific=true;}}}const useScientific=scientific||mantissa.length>20||order>4||order<-2||order-mantissa.length>0&&trailingZeros(mantissa)>0||zeroScientific;let returnVal="";if(!positive){returnVal+="-";}if(useScientific){returnVal+=mantissa.charAt(0);if(mantissa.length>1){returnVal+="."+mantissa.substring(1,mantissa.length);}if(order-1!=0){returnVal+=" x 10^"+(order-1);}}else {let wholePart="";let fractPart="";let needDot=true;if(order>0){if(mantissa.length>order){wholePart=mantissa.substring(0,order);fractPart=mantissa.substring(order,mantissa.length);}else {wholePart=mantissa;needDot=trailingZeros(mantissa)!=0;for(let i=0;i<order-mantissa.length;i++){wholePart+="0";}}}else {for(let i=0;i<-order;i++){fractPart+="0";}fractPart+=mantissa;}returnVal+=(wholePart==""?"0":wholePart)+(needDot?".":"")+fractPart;}return returnVal}function trailingZeros(mantissa){let zeros=0;for(let i=mantissa.length-1;i>=0;i--){const c=mantissa.charAt(i);if(c=="0"){zeros++;}else {return zeros}}return zeros}function parseSign(s){let beginning=true;let seenDot=false;let seenSomething=false;let zeros="";let all="";let pos=true;for(let i=0;i<s.length;i++){const c=s.charAt(i);if(c>="1"&&c<="9"){all+=zeros+c;zeros="";seenSomething=true;beginning=false;}else if(c=="0"){if(seenDot){if(seenSomething){all+=zeros+c;zeros="";}}else {if(seenSomething){zeros+=c;}}beginning=false;}else if(!seenDot&&c=="."){all+=zeros;zeros="";seenDot=true;beginning=false;}else if(c=="e"||c=="E"&&i+1<s.length){parseInt(s.substring(i+1,s.length));i=s.length;}else if(beginning&&(c=="+"||c=="-")){if(c=="-"){pos=!pos;}}}if(all==""){return true}return pos}function parseMantissa(s){let seenDot=false;let seenSomething=false;let zeros="";let leadZeros="";let all="";for(let i=0;i<s.length;i++){const c=s.charAt(i);if(c>="1"&&c<="9"){all+=zeros+c;zeros="";seenSomething=true;}else if(c=="0"){if(seenDot){if(seenSomething){all+=zeros+c;zeros="";}else {leadZeros+=c;}}else {if(seenSomething){leadZeros+=c;zeros+=c;}else {leadZeros+=c;}}}else if(!seenDot&&c=="."){all+=zeros;zeros="";seenDot=true;}else if(c=="e"||c=="E"&&i+1<s.length){parseInt(s.substring(i+1,s.length));i=s.length;}else ;}if(all==""){return leadZeros}return all}function parseOrder(s){let seenDot=false;let seenSomething=false;let zeros="";let all="";let decPlaces=0;let totalDecs=0;for(let i=0;i<s.length;i++){const c=s.charAt(i);if(c>="1"&&c<="9"){all+=zeros+c;zeros="";seenSomething=true;if(!seenDot){totalDecs++;decPlaces++;}}else if(c=="0"){if(seenDot){if(seenSomething){all+=zeros+c;zeros="";}else {decPlaces--;}}else {totalDecs++;if(seenSomething){decPlaces++;zeros+=c;}}}else if(!seenDot&&c=="."){all+=zeros;zeros="";seenDot=true;}else if(c=="e"||c=="E"&&i+1<s.length){const raised=parseInt(s.substring(i+1,s.length));decPlaces+=raised;totalDecs+=raised;i=s.length;}else ;}if(all==""){return totalDecs}return decPlaces}function round(mantissa,digits){const last=mantissa.length-digits-1;if(last<0){return ""}if(last>=mantissa.length-1){return mantissa}const nextToLast=mantissa.charAt(last+1);const lastChar=mantissa.charAt(last);let roundUp=false;if(nextToLast>"5"){roundUp=true;}else if(nextToLast=="5"){for(let j=last+2;j<mantissa.length;j++){if(mantissa.charAt(j)!="0"){roundUp=true;}}if(lastChar%2==1){roundUp=true;}}let result="";for(let i=last;i>=0;i--){const c=mantissa.charAt(i);if(roundUp){let nextChar;if(c=="9"){nextChar="0";}else {switch(c){case "0":nextChar="1";break;case "1":nextChar="2";break;case "2":nextChar="3";break;case "3":nextChar="4";break;case "4":nextChar="5";break;case "5":nextChar="6";break;case "6":nextChar="7";break;case "7":nextChar="8";break;case "8":nextChar="9";break}roundUp=false;}result=nextChar+result;}else {result=c+result;}}if(roundUp){result="1"+result;}return result}
|
|
2120
2107
|
|
|
2121
|
-
const registerAllWidgetsForTesting=()=>{registerWidgets(allWidgets);replaceDeprecatedWidgets();};
|
|
2108
|
+
const registerAllWidgetsForTesting=()=>{registerCoreWidgets();registerWidgets(allWidgets);replaceDeprecatedWidgets();};
|
|
2122
2109
|
|
|
2123
2110
|
function getWidgetTypeByWidgetId(WidgetId,widgetMap){const widget=widgetMap[WidgetId];return widget?.type??null}function getWidgetSubTypeByWidgetId(widgetId,widgetMap){const widget=widgetMap[widgetId];const widgetType=widget?.type??null;switch(widgetType){case "interactive-graph":const graph=widget.options.graph;return graph?.type??null;default:return null}}function contentHasWidgetType(type,content,widgetMap){return getWidgetIdsFromContentByType(type,content,widgetMap).length>0}function getWidgetsMapFromItemData(itemData){return itemData.question.widgets}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}
|
|
2124
2111
|
|
|
@@ -2132,7 +2119,7 @@ ${items.join("\n")}
|
|
|
2132
2119
|
| --- | --- |`;const tableRows=left.map((leftItem,index)=>{return `| ${leftItem} | ${right[index]} |`});const table=[tableHeader,...tableRows].join("\n");const matcherWidgetExplanation="The user needs to move items in the right column to match the correct option on the left. The order of items on the right side will be different from what the user sees.";context=context.replace(`[[☃ ${widgetID}]]`,`${matcherWidgetExplanation}
|
|
2133
2120
|
${table}`);}break;case "numeric-input":case "input-number":case "expression":context=context.replace(`[[☃ ${widgetID}]]`,"?");break;default:context=context.replace(`[[☃ ${widgetID}]]`,`[[Unsupported ${widget.type} widget: Explain to the user that you are unable to understand the content in this widget and ask them to describe it.]]`);}});return context}function getImagesWithoutAltData(perseusRenderer){if(!perseusRenderer.widgets){return ""}const imgsWithoutAltData=[];Object.entries(perseusRenderer.widgets).forEach(([widgetId,widget])=>{if(!widget.options){return}if(widget.type==="image"&&!widget.options.alt&&widget.options.backgroundImage?.url){imgsWithoutAltData.push({widgetId,imgUrl:widget.options.backgroundImage.url});}});return JSON.stringify(imgsWithoutAltData)}const INDIVIDUAL_ANSWER_WIDGETS=["interactive-graph","categorizer","grapher"];const SUPPORTED_WIDGETS=["radio","numeric-input","input-number","expression",...INDIVIDUAL_ANSWER_WIDGETS];const isWrongAnswerSupported=(widgetIds,widgetMap)=>{return widgetIds.length!==0&&widgetIds.every(widgetId=>SUPPORTED_WIDGETS.includes(getWidgetTypeByWidgetId(widgetId,widgetMap)))};const shouldHaveIndividualAnswer=(widgetId,widgetMap)=>{return INDIVIDUAL_ANSWER_WIDGETS.includes(getWidgetTypeByWidgetId(widgetId,widgetMap))};const getAnswerFromUserInput=(widgetType,userInput)=>{switch(widgetType){case "categorizer":return userInput.values;case "input-number":return userInput.currentValue;case "numeric-input":return userInput.currentValue;case "radio":return userInput.choicesSelected}return userInput};const getCorrectAnswerForWidgetId=(widgetId,itemData)=>{const rubric=itemData.question.widgets[widgetId].options;const widgetMap=getWidgetsMapFromItemData(itemData);const widgetType=getWidgetTypeByWidgetId(widgetId,widgetMap);const widget=getWidgetExport(widgetType);return widget?.getOneCorrectAnswerFromRubric?.(rubric)};const isWidgetIdInContent=(perseusItem,widgetId)=>{return perseusItem.question.content.indexOf(widgetId)!==-1};const getValidWidgetIds=perseusItem=>{const{widgets}=perseusItem.question;return keys(widgets).filter(id=>isWidgetIdInContent(perseusItem,id))};
|
|
2134
2121
|
|
|
2135
|
-
function generateTestRadioWidget(){return {type:"radio",options:{choices:[]}}}function generateTestInteractiveGraphWidget(){return {type:"interactive-graph",options:{step:[1,1],gridStep:[1,1],snapStep:[1,1],markings:"graph",labels:["x","y"],showProtractor:false,range:[[-10,10],[-10,10]],graph:{type:"angle"},correct:{type:"angle"}}}}function generateTestCategorizerWidget(){return {type:"categorizer",options:{items:[],categories:[],randomizeItems:false,static:false,values:[]}}}function generateTestExpressionWidget(){return {type:"expression",options:{answerForms:[],buttonSets:["basic"],functions:[],times:false}}}function generateTestNumericInputWidget(){return {type:"numeric-input",options:{answers:[],labelText:"",size:"normal",coefficient:false,static:false}}}
|
|
2122
|
+
function generateTestRadioWidget(){return {type:"radio",options:{choices:[]}}}function generateTestInteractiveGraphWidget(){return {type:"interactive-graph",options:{step:[1,1],gridStep:[1,1],snapStep:[1,1],markings:"graph",labels:["x","y"],lockedFigures:[],showProtractor:false,range:[[-10,10],[-10,10]],graph:{type:"angle"},correct:{type:"angle"}}}}function generateTestCategorizerWidget(){return {type:"categorizer",options:{items:[],categories:[],randomizeItems:false,static:false,values:[]}}}function generateTestExpressionWidget(){return {type:"expression",options:{answerForms:[],buttonSets:["basic"],functions:[],times:false}}}function generateTestNumericInputWidget(){return {type:"numeric-input",options:{answers:[],labelText:"",size:"normal",coefficient:false,static:false}}}
|
|
2136
2123
|
|
|
2137
2124
|
const widgetNameToEnum={categorizer:"CATEGORIZER","cs-program":"CS_PROGRAM",definition:"DEFINITION","deprecated-standin":"DEPRECATED_STANDIN",dropdown:"DROPDOWN",explanation:"EXPLANATION",expression:"EXPRESSION","graded-group-set":"GRADED_GROUP_SET","graded-group":"GRADED_GROUP",grapher:"GRAPHER",group:"GROUP",iframe:"IFRAME",image:"IMAGE","input-number":"INPUT_NUMBER",interaction:"INTERACTIVE","interactive-graph":"INTERACTIVE_GRAPH","label-image":"LABEL_IMAGE","lights-puzzle":"LIGHTS_PUZZLE",matcher:"MATCHER",matrix:"MATRIX",measurer:"MEASURER","molecule-renderer":"MOLECULE","number-line":"NUMBER_LINE","numeric-input":"NUMERIC_INPUT",orderer:"ORDERER",passage:"PASSAGE","passage-ref":"PASSAGE_REF","passage-ref-target":"PASSAGE_REF_TARGET","phet-simulation":"PHET_SIMULATION",plotter:"PLOTTER","python-program":"PYTHON_PROGRAM","reaction-diagram":"REACTION_DIAGRAM",radio:"RADIO",sequence:"SEQUENCE",simulator:"SIMULATOR",sorter:"SORTER",table:"TABLE",video:"VIDEO"};function convertWidgetNameToEnum(name){const widgetEnum=widgetNameToEnum[name];if(!widgetEnum){throw new Error(`Unknown widget name: ${name}`)}return widgetEnum}
|
|
2138
2125
|
|