@khanacademy/perseus 66.2.2 → 66.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.css +13 -1
- package/dist/es/index.css.map +1 -1
- package/dist/es/index.js +55 -55
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +13 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +57 -54
- package/dist/index.js.map +1 -1
- package/dist/widget-ai-utils/categorizer/categorizer-ai-utils.d.ts +1 -1
- package/dist/widget-ai-utils/matrix/matrix-ai-utils.d.ts +1 -1
- package/dist/widgets/categorizer/categorizer.d.ts +3 -7
- package/dist/widgets/dropdown/dropdown.d.ts +10 -10
- package/dist/widgets/expression/expression.d.ts +14 -21
- package/dist/widgets/graded-group/graded-group.d.ts +1 -2
- package/dist/widgets/graded-group-set/graded-group-set.d.ts +1 -2
- package/dist/widgets/grapher/grapher.d.ts +2 -34
- package/dist/widgets/group/group.d.ts +1 -2
- package/dist/widgets/image/image.d.ts +1 -2
- package/dist/widgets/input-number/input-number.d.ts +1 -4
- package/dist/widgets/interactive-graphs/interactive-graph-question-builder.d.ts +7 -0
- package/dist/widgets/interactive-graphs/interactive-graph.d.ts +16 -1
- package/dist/widgets/interactive-graphs/mafs-graph.d.ts +1 -0
- package/dist/widgets/interactive-graphs/reducer/use-graph-config.d.ts +2 -1
- package/dist/widgets/interactive-graphs/stateful-mafs-graph.d.ts +1 -0
- package/dist/widgets/matrix/matrix.d.ts +1 -11
- package/dist/widgets/passage/passage.d.ts +1 -8
- package/dist/widgets/passage-ref/passage-ref.d.ts +0 -5
- package/dist/widgets/passage-ref-target/passage-ref-target.d.ts +0 -1
- package/dist/widgets/plotter/plotter.d.ts +0 -1
- package/dist/widgets/radio/base-radio.d.ts +1 -0
- package/dist/widgets/radio/choice.new.d.ts +9 -26
- package/dist/widgets/radio/multiple-choice-component.new.d.ts +3 -25
- package/dist/widgets/radio/multiple-choice-widget.new.d.ts +17 -1
- package/dist/widgets/video/video.d.ts +1 -2
- package/package.json +42 -42
- package/dist/widgets/radio/choice-none-above.new.d.ts +0 -14
- package/dist/widgets/radio/focus-ring.new.d.ts +0 -19
- package/dist/widgets/radio/multiple-choice-option.new.d.ts +0 -11
- package/dist/widgets/radio/option-status.new.d.ts +0 -23
package/dist/index.js
CHANGED
|
@@ -30,12 +30,14 @@ var pureMarkdown = require('@khanacademy/pure-markdown');
|
|
|
30
30
|
var IconButton = require('@khanacademy/wonder-blocks-icon-button');
|
|
31
31
|
var caretLeftIcon = require('@phosphor-icons/core/regular/caret-left.svg');
|
|
32
32
|
var caretRightIcon = require('@phosphor-icons/core/regular/caret-right.svg');
|
|
33
|
+
var wonderBlocksIcon = require('@khanacademy/wonder-blocks-icon');
|
|
34
|
+
var checkIcon = require('@phosphor-icons/core/bold/check-bold.svg');
|
|
35
|
+
var minusIcon = require('@phosphor-icons/core/bold/minus-circle-bold.svg');
|
|
33
36
|
var Banner = require('@khanacademy/wonder-blocks-banner');
|
|
34
37
|
var wonderBlocksDropdown = require('@khanacademy/wonder-blocks-dropdown');
|
|
35
38
|
var Button = require('@khanacademy/wonder-blocks-button');
|
|
36
39
|
var caretDown = require('@phosphor-icons/core/regular/caret-down.svg');
|
|
37
40
|
var caretUp = require('@phosphor-icons/core/regular/caret-up.svg');
|
|
38
|
-
var wonderBlocksIcon = require('@khanacademy/wonder-blocks-icon');
|
|
39
41
|
var wonderBlocksLabeledField = require('@khanacademy/wonder-blocks-labeled-field');
|
|
40
42
|
var warningCircleIcon = require('@phosphor-icons/core/regular/warning-circle.svg');
|
|
41
43
|
var KAS = require('@khanacademy/kas');
|
|
@@ -85,6 +87,8 @@ var SimpleMarkdown__default = /*#__PURE__*/_interopDefaultCompat(SimpleMarkdown)
|
|
|
85
87
|
var IconButton__default = /*#__PURE__*/_interopDefaultCompat(IconButton);
|
|
86
88
|
var caretLeftIcon__default = /*#__PURE__*/_interopDefaultCompat(caretLeftIcon);
|
|
87
89
|
var caretRightIcon__default = /*#__PURE__*/_interopDefaultCompat(caretRightIcon);
|
|
90
|
+
var checkIcon__default = /*#__PURE__*/_interopDefaultCompat(checkIcon);
|
|
91
|
+
var minusIcon__default = /*#__PURE__*/_interopDefaultCompat(minusIcon);
|
|
88
92
|
var Banner__default = /*#__PURE__*/_interopDefaultCompat(Banner);
|
|
89
93
|
var Button__default = /*#__PURE__*/_interopDefaultCompat(Button);
|
|
90
94
|
var caretDown__default = /*#__PURE__*/_interopDefaultCompat(caretDown);
|
|
@@ -1451,7 +1455,7 @@ var a11y = aphrodite.StyleSheet.create({srOnly:{border:0,clip:"rect(0,0,0,0)",he
|
|
|
1451
1455
|
|
|
1452
1456
|
const debounce=(func,delay)=>{let timer=null;return (...args)=>{if(timer){clearTimeout(timer);}timer=window.setTimeout(()=>{func(...args);},delay);}};
|
|
1453
1457
|
|
|
1454
|
-
class InnerMathInput extends React__namespace.Component{componentDidMount(){this.mathField()?.latex(this.props.value);}openKeypad(){if(this.props.buttonsVisible==="never"){return}this.setState({keypadOpen:true});}closeKeypad(){this.setState({keypadOpen:false});}render(){let className=classNames__default.default({"perseus-math-input":true,"mq-editable-field":true,"mq-math-mode":true});const popoverContentUniqueId=uuid.v4().slice(0,8);if(this.props.className){className=className+" "+this.props.className;}return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$
|
|
1458
|
+
class InnerMathInput extends React__namespace.Component{componentDidMount(){this.mathField()?.latex(this.props.value);}openKeypad(){if(this.props.buttonsVisible==="never"){return}this.setState({keypadOpen:true});}closeKeypad(){this.setState({keypadOpen:false});}render(){let className=classNames__default.default({"perseus-math-input":true,"mq-editable-field":true,"mq-math-mode":true});const popoverContentUniqueId=uuid.v4().slice(0,8);if(this.props.className){className=className+" "+this.props.className;}return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$H.outerWrapper,this.state.focused&&styles$H.wrapperFocused],children:jsxRuntimeExports.jsxs("div",{style:{display:"flex",padding:1},onClick:e=>{e.stopPropagation();const mathField=this.mathField();if(!mathField){return}this.setState({cursorContext:mathInput.getCursorContext(mathField)});},children:[jsxRuntimeExports.jsx("span",{className:className,ref:ref=>this.__mathFieldWrapperRef=ref,onFocus:()=>this.focus(),onBlur:()=>this.blur()}),jsxRuntimeExports.jsx(wonderBlocksPopover.Popover,{opened:this.state.keypadOpen,dismissEnabled:true,rootBoundary:"document","aria-label":this.context.strings.mathInputTitle,"aria-describedby":`popover-content-${popoverContentUniqueId}`,content:()=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(wonderBlocksTypography.HeadingMedium,{id:`popover-content-${popoverContentUniqueId}`,style:a11y.srOnly,children:this.context.strings.mathInputDescription}),jsxRuntimeExports.jsx(wonderBlocksPopover.PopoverContentCore,{style:styles$H.popoverContent,children:jsxRuntimeExports.jsx(mathInput.DesktopKeypad,{onAnalyticsEvent:this.props.onAnalyticsEvent,extraKeys:this.props.extraKeys,onClickKey:this.handleKeypadPress,cursorContext:this.state.cursorContext,convertDotToTimes:this.props.convertDotToTimes,...this.props.keypadButtonSets??mapButtonSets(this.props?.buttonSets),showDismiss:true})})]}),children:this.props.buttonsVisible==="never"?jsxRuntimeExports.jsx(MathInputIcon,{hovered:false,focused:false,active:false}):jsxRuntimeExports.jsx(Clickable__default.default,{"aria-label":this.state.keypadOpen?this.context.strings.closeKeypad:this.context.strings.openKeypad,role:"button",onClick:()=>this.state.keypadOpen?this.closeKeypad():this.openKeypad(),children:props=>jsxRuntimeExports.jsx(MathInputIcon,{active:this.state.keypadOpen,...props})})})]})})}constructor(...args){super(...args),this.__mathFieldWrapperRef=null,this.__mathField=null,this.state={focused:false,keypadOpen:this.props.buttonsVisible==="always"?true:false,cursorContext:mathInput.CursorContext.NONE},this.insert=value=>{const input=this.mathField();const{locale}=this.context;const customKeyTranslator={...mathInput.getKeyTranslator(locale,this.context.strings),FRAC:mathQuill=>{const contents=mathQuill.latex();mathQuill.typedText("/");if(mathQuill.latex()===contents){mathQuill.cmd("\\frac");}}};const inputModifier=customKeyTranslator[value];if(inputModifier){inputModifier(input,value);input?.focus();return}if(___default.default(value).isFunction()){value(input);}else if(value[0]==="\\"){input?.cmd(value).focus();}else {input?.write(value).focus();}input?.focus();},this.mathField=()=>{if(!this.__mathField&&this.__mathFieldWrapperRef){const{locale}=this.context;this.__mathField=mathInput.createMathField(this.__mathFieldWrapperRef,locale,this.props.mathInputStrings,baseConfig=>({...baseConfig,handlers:{edit:debounce(mathField=>{let value=mathField.latex();value=value.replace(/<>/g,"\\ne");if(mathInput.convertDotToTimesByLocale(locale,this.props.convertDotToTimes)){value=value.replace(/\\cdot/g,"\\times");const left=mathField.cursor()[mathInput.mathQuillInstance.L];if(left&&left.ctrlSeq==="\\cdot "){mathField.controller().backspace();mathField.cmd("\\times");}}else {value=value.replace(/\\times/g,"\\cdot");}if(this.props.value!==value){this.props.onChange(value);}this.setState({cursorContext:mathInput.getCursorContext(mathField)});},100),enter:()=>{if(this.__mathFieldWrapperRef){$__default.default(this.__mathFieldWrapperRef).submit();}},upOutOf:mathField=>{mathField.typedText("^");}}}));}this.__mathField?.setAriaLabel(this.props.ariaLabel);return this.__mathField},this.focus=()=>{this.mathField()?.focus();this.setState({focused:true});},this.blur=()=>this.setState({focused:false}),this.handleKeypadPress=(key,e)=>{const{locale}=this.context;const translator=mathInput.getKeyTranslator(locale,this.context.strings)[key];const mathField=this.mathField();if(mathField){if(translator){translator(mathField,key);}this.setState({cursorContext:mathInput.getCursorContext(mathField)});}if(e?.type==="click"){this.focus();}if(key==="DISMISS"){this.closeKeypad();}};}}InnerMathInput.contextType=PerseusI18nContext;InnerMathInput.defaultProps={value:"",convertDotToTimes:false};class MathInput extends React__namespace.Component{blur(){this.inputRef.current?.blur();}focus(){this.inputRef.current?.focus();}insert(value){this.inputRef.current?.insert(value);}render(){return jsxRuntimeExports.jsx(InnerMathInput,{...this.props,ref:this.inputRef,mathInputStrings:this.context.strings})}constructor(...args){super(...args),this.inputRef=React__namespace.createRef();}}MathInput.contextType=mathInput.MathInputI18nContext;MathInput.defaultProps={ariaLabel:"Math input"};const MathInputIcon=({hovered,focused,active})=>{let fillColor;switch(true){case focused||active:fillColor=wonderBlocksTokens.color.white;break;case hovered:fillColor=wonderBlocksTokens.color.blue;break;default:fillColor=wonderBlocksTokens.color.offBlack;break}const dynamicClass=active||focused?styles$H.iconActive:styles$H.iconInactive;return jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:[styles$H.iconContainer,dynamicClass],children:jsxRuntimeExports.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",fill:fillColor,viewBox:"0 0 256 256",children:jsxRuntimeExports.jsx("path",{d:"M112,72a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16h64A8,8,0,0,1,112,72Zm-8,104H80V152a8,8,0,0,0-16,0v24H40a8,8,0,0,0,0,16H64v24a8,8,0,0,0,16,0V192h24a8,8,0,0,0,0-16Zm48,0h64a8,8,0,0,0,0-16H152a8,8,0,0,0,0,16Zm64,16H152a8,8,0,0,0,0,16h64a8,8,0,0,0,0-16Zm-61.66-90.34a8,8,0,0,0,11.32,0L184,83.31l18.34,18.35a8,8,0,0,0,11.32-11.32L195.31,72l18.35-18.34a8,8,0,0,0-11.32-11.32L184,60.69,165.66,42.34a8,8,0,0,0-11.32,11.32L172.69,72,154.34,90.34A8,8,0,0,0,154.34,101.66Z"})})})};const mapButtonSets=buttonSets=>{const keypadButtonSets={};if(!buttonSets){return keypadButtonSets}buttonSets.forEach(buttonSet=>{switch(buttonSet){case "advanced relations":keypadButtonSets.advancedRelations=true;break;case "basic relations":keypadButtonSets.basicRelations=true;break;case "basic+div":keypadButtonSets.divisionKey=true;break;case "logarithms":keypadButtonSets.logarithms=true;break;case "prealgebra":keypadButtonSets.preAlgebra=true;break;case "trig":keypadButtonSets.trigonometry=true;break;case "scientific":keypadButtonSets.scientific=true;break;}});return keypadButtonSets};const inputFocused={borderWidth:2,borderColor:wonderBlocksTokens.color.blue,margin:-1};const styles$H=aphrodite.StyleSheet.create({iconContainer:{display:"flex",justifyContent:"center",height:"100%",padding:wonderBlocksTokens.spacing.xxxSmall_4,borderRadius:1},iconInactive:{border:"2px solid transparent",backgroundColor:wonderBlocksTokens.color.offBlack8},iconActive:{border:`2px solid ${wonderBlocksTokens.color.white}`,backgroundColor:wonderBlocksTokens.color.offBlack64},outerWrapper:{display:"inline-block",borderStyle:"solid",borderWidth:1,borderColor:wonderBlocksTokens.color.offBlack50,borderRadius:3,background:wonderBlocksTokens.color.white,":hover":inputFocused},wrapperFocused:inputFocused,popoverContent:{padding:0,paddingBottom:wonderBlocksTokens.spacing.xxSmall_6,maxWidth:"initial"}});
|
|
1455
1459
|
|
|
1456
1460
|
let _dependencies=null;const setDependencies=dependencies=>{_dependencies=dependencies;};const getDependencies=()=>{if(_dependencies){return _dependencies}throw new Error(["Perseus has not been provided required dependencies.","setDependencies(dependencies) must be called first.","Make sure Perseus is being imported from javascript/perseus/perseus.js."].join("\n"))};const DependenciesContext=React__namespace.createContext({analytics:{onAnalyticsEvent:async()=>{}},useVideo:()=>{throw new Error("useVideo dependency not provided in Perseus dependencies")}});const useDependencies=()=>{const deps=React__namespace.useContext(DependenciesContext);return deps};
|
|
1457
1461
|
|
|
@@ -1471,7 +1475,7 @@ const ApiOptions={propTypes:PropTypes__default.default.shape({isArticle:PropType
|
|
|
1471
1475
|
|
|
1472
1476
|
const getPromptJSON$t=(renderProps,userInput)=>{return {type:"expression",label:renderProps.visibleLabel,userInput:{value:userInput}}};
|
|
1473
1477
|
|
|
1474
|
-
const englishOperators={arctg:"arctan",cosec:"csc",cossec:"csc",cotg:"cot",ctg:"cot",sen:"sin",tg:"tan"};const anglicizeOperators=tex=>{return tex.replace(/\\operatorname{([a-z]+)}/g,(_,op)=>`\\${englishOperators[op]??op} `)};const normalizeTex=tex=>{return anglicizeOperators(tex)};class Expression extends React__namespace.Component{getUserInput(){return normalizeTex(this.props.userInput)}getPromptJSON(){return getPromptJSON$t(this.props,normalizeTex(this.props.userInput))}focusInputPath(inputPath){this.refs.input.focus();}blurInputPath(inputPath){if(typeof this.refs.input?.blur==="function"){this.refs.input?.blur();}}insert(keyPressed){this.refs.input.insert(keyPressed);}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,value:this.props.userInput}}render(){if(this.props.apiOptions.customKeypad){return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:aphrodite.css(styles$
|
|
1478
|
+
const englishOperators={arctg:"arctan",cosec:"csc",cossec:"csc",cotg:"cot",ctg:"cot",sen:"sin",tg:"tan"};const anglicizeOperators=tex=>{return tex.replace(/\\operatorname{([a-z]+)}/g,(_,op)=>`\\${englishOperators[op]??op} `)};const normalizeTex=tex=>{return anglicizeOperators(tex)};class Expression extends React__namespace.Component{getUserInput(){return normalizeTex(this.props.userInput)}getPromptJSON(){return getPromptJSON$t(this.props,normalizeTex(this.props.userInput))}focusInputPath(inputPath){this.refs.input.focus();}blurInputPath(inputPath){if(typeof this.refs.input?.blur==="function"){this.refs.input?.blur();}}insert(keyPressed){this.refs.input.insert(keyPressed);}getKeypadConfiguration(){return {keypadType:"EXPRESSION",extraKeys:this.props.extraKeys,times:this.props.times}}getSerializedState(){const{userInput:_,answerForms:__,...rest}=this.props;return {...rest,value:this.props.userInput,keypadConfiguration:this.getKeypadConfiguration()}}render(){const keypadConfiguration=this.getKeypadConfiguration();if(this.props.apiOptions.customKeypad){return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:aphrodite.css(styles$G.mobileLabelInputWrapper),children:[!!this.props.visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.LabelSmall,{htmlFor:this._textareaId,tag:"label",children:this.props.visibleLabel}),jsxRuntimeExports.jsx(mathInput.KeypadInput,{ref:"input",ariaLabel:this.props.ariaLabel||this.context.strings.mathInputBox,value:this.props.userInput,keypadElement:this.props.keypadElement,onChange:this.changeAndTrack,onFocus:()=>{this.props.keypadElement?.configure(keypadConfiguration,()=>{if(this._isMounted){this._handleFocus();}});},onBlur:this._handleBlur})]})}return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:aphrodite.css(styles$G.desktopLabelInputWrapper),children:[!!this.props.visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.LabelSmall,{htmlFor:this._textareaId,tag:"label",children:this.props.visibleLabel}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-expression",children:jsxRuntimeExports.jsx(MathInput,{ref:"input",value:this.props.userInput,onChange:this.changeAndTrack,convertDotToTimes:this.props.times,buttonSets:this.props.buttonSets,onFocus:this._handleFocus,onBlur:this._handleBlur,ariaLabel:this.props.ariaLabel||this.context.strings.mathInputBox,extraKeys:keypadConfiguration.extraKeys,onAnalyticsEvent:this.props.analytics?.onAnalyticsEvent??(async()=>{})})})]})}constructor(...args){super(...args),this._textareaId=`expression_textarea_${Date.now()}`,this._isMounted=false,this.displayName="Expression",this.componentDidMount=()=>{this._isMounted=true;if(this.refs.input){const isMobile=this.props.apiOptions.customKeypad;const container=ReactDOM__namespace.default.findDOMNode(this.refs.input);const selector=isMobile?".mq-textarea > span":"textarea";const inputElement=container.querySelector(selector);inputElement?.setAttribute("id",this._textareaId);}},this.componentWillUnmount=()=>{this._isMounted=false;},this.changeAndTrack=(userInput,cb)=>{this.props.handleUserInput(normalizeTex(userInput),cb);this.props.trackInteraction();},this._handleFocus=()=>{this.props.analytics?.onAnalyticsEvent({type:"perseus:expression-focused",payload:null});this.props.onFocus([]);},this._handleBlur=()=>{this.props.onBlur([]);},this.focus=()=>{if(this.props.apiOptions.customKeypad){this.refs.input.focus();}return true},this.getInputPaths=()=>{return [[]]};}}Expression.contextType=PerseusI18nContext;Expression.defaultProps={times:false,functions:[],buttonSets:["basic","trig","prealgebra","logarithms"],onFocus:()=>{},onBlur:()=>{},apiOptions:ApiOptions.defaults,linterContext:PerseusLinter.linterContextDefault,userInput:""};const styles$G=aphrodite.StyleSheet.create({mobileLabelInputWrapper:{padding:"15px 4px 0"},desktopLabelInputWrapper:{margin:"5px 5px 0"}});const ExpressionWithDependencies=React__namespace.forwardRef((props,ref)=>{const deps=useDependencies();return jsxRuntimeExports.jsx(Expression,{ref:ref,analytics:deps.analytics,...props})});function getUserInputFromSerializedState$i(serializedState){return normalizeTex(serializedState.value)}function getStartUserInput$j(){return ""}function getOneCorrectAnswerFromRubric$1(rubric){const correctAnswers=(rubric.answerForms||[]).filter(answerForm=>answerForm.considered==="correct");if(correctAnswers.length===0){return}return correctAnswers[0].value}var Expression$1 = {name:"expression",displayName:"Expression / Equation",widget:ExpressionWithDependencies,version:perseusCore.expressionLogic.version,isLintable:true,getOneCorrectAnswerFromRubric: getOneCorrectAnswerFromRubric$1,getStartUserInput: getStartUserInput$j,getUserInputFromSerializedState: getUserInputFromSerializedState$i};
|
|
1475
1479
|
|
|
1476
1480
|
class SimpleKeypadInput extends React__namespace.Component{componentDidMount(){this._isMounted=true;}componentWillUnmount(){this._isMounted=false;}focus(){this.inputRef.current?.focus(this.context.setKeypadActive);}blur(){this.inputRef.current?.blur();}getValue(){return this.props.value}render(){const _this=this;const{keypadElement,onFocus,value,...rest}=_this.props;return jsxRuntimeExports.jsx(mathInput.KeypadInput,{ref:this.inputRef,keypadElement:keypadElement,onFocus:()=>{if(keypadElement){keypadElement.configure({keypadType:"FRACTION"},()=>{if(_this._isMounted){onFocus?.();}});}else {onFocus?.();}},value:value==null?"":""+value,...rest})}constructor(...args){super(...args),this._isMounted=false,this.inputRef=React__namespace.createRef();}}SimpleKeypadInput.contextType=keypadContext.KeypadContext;SimpleKeypadInput.propTypes={keypadElement:mathInput.keypadElementPropType,onFocus:PropTypes__default.default.func,value:PropTypes__default.default.oneOfType([PropTypes__default.default.string,PropTypes__default.default.number])};
|
|
1477
1481
|
|
|
@@ -1481,7 +1485,7 @@ let lastId=0;function uniqueIdForInput(prefix="input-"){lastId++;return `${prefi
|
|
|
1481
1485
|
|
|
1482
1486
|
const defaultContext$2={assetStatuses:{},setAssetStatus:(assetKey,loaded)=>{}};const context$1=React__namespace.createContext(defaultContext$2);
|
|
1483
1487
|
|
|
1484
|
-
let supportsPassive=false;const nestedMap$2=function(children,func,context){if(Array.isArray(children)){return ___default.default.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=perseusScore.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 ___default.default(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$
|
|
1488
|
+
let supportsPassive=false;const nestedMap$2=function(children,func,context){if(Array.isArray(children)){return ___default.default.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=perseusScore.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 ___default.default(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$3(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);___default.default.defer(function(){callback(img.clientWidth,img.clientHeight);document.body?.removeChild(img);});}else {callback(img.width,img.height);}};img.src=perseusCore.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$3,getImageSize,getImageSizeModern:perseusCore.getImageSizeModern,getRealImageUrl:perseusCore.getRealImageUrl,isLabeledSVG:perseusCore.isLabeledSVG,getBaseUrl:perseusCore.getBaseUrl,getSvgUrl:perseusCore.getSvgUrl,getDataUrl:perseusCore.getDataUrl,textarea,unescapeMathMode: unescapeMathMode$1};
|
|
1485
1489
|
|
|
1486
1490
|
const Log={log:(message,extra)=>{getDependencies().Log.log(message,extra);},error:(message,kind,extra)=>{getDependencies().Log.error(message,kind,extra);}};
|
|
1487
1491
|
|
|
@@ -1669,7 +1673,7 @@ const arrayRules={fence:{match:SimpleMarkdown__default.default.defaultRules.fenc
|
|
|
1669
1673
|
|
|
1670
1674
|
const denylist=["key","ref","containerSizeClass","widgetId","onChange","problemNum","apiOptions","widgetIsOpen","questionCompleted","findWidgets","onRemove","id","onBlur","onFocus","trackInteraction","keypadElement","linterContext","isLastUsedWidget","handleUserInput","analytics","showSolutions","reviewMode","reviewModeRubric"];function excludeDenylistKeys(obj){if(obj==null){return obj}const rv={};for(const k of Object.keys(obj)){if(!denylist.includes(k)){rv[k]=obj[k];}}return rv}
|
|
1671
1675
|
|
|
1672
|
-
const exclamationIcon={path:"M6 11a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0-9a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1z",height:12,width:12};class Lint extends React__namespace.Component{componentDidMount(){this._positionTimeout=window.setTimeout(this.getPosition);}componentWillUnmount(){window.clearTimeout(this._positionTimeout);}render(){const{children,inline,blockHighlight,insideTable}=this.props;if(insideTable){if(inline){return jsxRuntimeExports.jsx("span",{"data-lint-inside-table":"true",children:children})}return jsxRuntimeExports.jsx("div",{"data-lint-inside-table":"true",children:children})}if(blockHighlight){return jsxRuntimeExports.jsxs("span",{className:aphrodite.css(styles$
|
|
1676
|
+
const exclamationIcon={path:"M6 11a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm0-9a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V3a1 1 0 0 1 1-1z",height:12,width:12};class Lint extends React__namespace.Component{componentDidMount(){this._positionTimeout=window.setTimeout(this.getPosition);}componentWillUnmount(){window.clearTimeout(this._positionTimeout);}render(){const{children,inline,blockHighlight,insideTable}=this.props;if(insideTable){if(inline){return jsxRuntimeExports.jsx("span",{"data-lint-inside-table":"true",children:children})}return jsxRuntimeExports.jsx("div",{"data-lint-inside-table":"true",children:children})}if(blockHighlight){return jsxRuntimeExports.jsxs("span",{className:aphrodite.css(styles$F.lintContainer,styles$F.lintContainerBlock),children:[this.renderLink(styles$F.radioWidgetHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}if(inline){return jsxRuntimeExports.jsxs("span",{className:aphrodite.css(styles$F.lintContainer),children:[this.renderLink(styles$F.inlineHoverTarget),jsxRuntimeExports.jsx("span",{children:children})]})}return jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$F.lintContainer),children:[this.renderLink(styles$F.hoverTarget),jsxRuntimeExports.jsx("div",{children:children})]})}constructor(...args){super(...args),this.state={tooltipAbove:true},this.getPosition=()=>{const rect=ReactDOM__namespace.default.findDOMNode(this).getBoundingClientRect();this.setState({tooltipAbove:rect.top>100});},this.renderLink=style=>{const tooltipAbove=this.state.tooltipAbove;let severityStyle;let warningText;let warningTextStyle;if(this.props.severity===1){severityStyle=styles$F.indicatorError;warningText="Error";warningTextStyle=styles$F.publishBlockingError;}else if(this.props.severity===2){severityStyle=styles$F.indicatorWarning;warningText="Warning";warningTextStyle=styles$F.warning;}else {severityStyle=styles$F.indicatorGuideline;warningText="Recommendation";warningTextStyle=styles$F.warning;}return jsxRuntimeExports.jsxs("a",{href:`https://khanacademy.org/r/linter-rules#${this.props.ruleName}`,target:"lint-help-window",className:aphrodite.css(style),children:[jsxRuntimeExports.jsx("span",{className:aphrodite.css(styles$F.indicator,severityStyle),children:this.props.severity===1&&jsxRuntimeExports.jsx(InlineIcon,{...exclamationIcon})}),jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$F.tooltip,tooltipAbove&&styles$F.tooltipAbove),children:[this.props.message.split("\n\n").map((m,i)=>jsxRuntimeExports.jsxs("p",{className:aphrodite.css(styles$F.tooltipParagraph),children:[jsxRuntimeExports.jsxs("span",{className:aphrodite.css(warningTextStyle),children:[warningText,":"," "]}),m]},i)),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$F.tail,tooltipAbove&&styles$F.tailAbove)})]})]})};}}const styles$F=aphrodite.StyleSheet.create({lintContainer:{position:"relative"},lintContainerBlock:{display:"block"},hoverTarget:{position:"absolute",top:0,right:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ div":{outline:"1px solid "+warningColor},":hover ~ div div[data-lint-inside-table]":{outline:"1px solid "+warningColor},":hover ~ div span[data-lint-inside-table]":{backgroundColor:warningColor,color:white}},inlineHoverTarget:{float:"right",position:"relative",marginRight:-40,display:"block",width:24,height:24,":hover > span":{backgroundColor:warningColorHover},":hover div":{display:"block"},":hover ~ span":{backgroundColor:warningColor,color:white}},radioWidgetHoverTarget:{position:"absolute",left:-40,display:"block",width:24,height:24,minWidth:264,":hover > span":{backgroundColor:warningColorHover},":hover > div":{display:"block",padding:8,width:280},":hover > div > div":{left:8},":hover ~ span":{backgroundColor:warningColor,color:white}},indicator:{alignItems:"center",borderRadius:4,color:"white",display:"flex",fontSize:12,height:8,justifyContent:"center",margin:8,width:8},indicatorError:{backgroundColor:"#be2612",borderRadius:8,height:16,width:16},indicatorWarning:{backgroundColor:"#f86700"},indicatorGuideline:{backgroundColor:"#ffbe26"},tooltip:{position:"absolute",right:-12,display:"none",zIndex:1e3,color:white,backgroundColor:gray17,opacity:.9,fontFamily:baseFontFamily,fontSize:"12px",lineHeight:"15px",width:"320px",borderRadius:"4px"},tooltipAbove:{bottom:32},tail:{position:"absolute",top:-12,right:16,width:0,height:0,borderLeft:"8px solid transparent",borderRight:"8px solid transparent",borderBottom:"12px solid "+gray17},tailAbove:{bottom:-12,borderBottom:"none",borderTop:"12px solid "+gray17,top:"auto"},tooltipParagraph:{margin:12},warning:{color:warningColor,fontFamily:boldFontFamily},publishBlockingError:{color:publishBlockingErrorColor}});
|
|
1673
1677
|
|
|
1674
1678
|
const rules$1={...pureMarkdown.pureMarkdownRules,columns:{...pureMarkdown.pureMarkdownRules.columns,react:(node,output,state)=>{return jsxRuntimeExports.jsxs("div",{className:"perseus-two-columns",children:[jsxRuntimeExports.jsx("div",{className:"perseus-column",children:jsxRuntimeExports.jsx("div",{className:"perseus-column-content",children:output(node.col1,state)})}),jsxRuntimeExports.jsx("div",{className:"perseus-column",children:jsxRuntimeExports.jsx("div",{className:"perseus-column-content",children:output(node.col2,state)})})]},state.key)}},crowdinId:{...pureMarkdown.pureMarkdownRules.crowdinId,react:(node,output,state)=>node.id},table:{...pureMarkdown.pureMarkdownRules.table,react:function(node,output,state){const table=SimpleMarkdown__default.default.defaultRules.table.react(node,output,state);if(!state.isMobile){return table}return React__namespace.cloneElement(table,{tabIndex:0})}},titledTable:{...pureMarkdown.pureMarkdownRules.titledTable,react:(node,output,state)=>{let contents;if(!node.table){contents="//invalid table//";}else if(node.table.type==="lint"){if(node.table.content?.type==="table"){contents=rules$1.lint.react({...node.table,content:{...node,table:node.table.content}},output,{...state,unwrapTitledTableContents:true});}else {contents=rules$1.lint.react(node.table,output,state);}}else {const tableOutput=SimpleMarkdown__default.default.defaultRules.table.react(node.table,output,state);const caption=jsxRuntimeExports.jsx("caption",{className:"perseus-table-title",children:output(node.title,state)},"caption");contents=React__namespace.cloneElement(tableOutput,null,[caption,...tableOutput.props.children]);}if(state.unwrapTitledTableContents){return contents}return jsxRuntimeExports.jsx("div",{className:"perseus-titled-table",children:contents},state.key)}},widget:{...pureMarkdown.pureMarkdownRules.widget,react:(node,output,state)=>{return jsxRuntimeExports.jsx("em",{children:`[Widget: ${node.id}]`},state.key)}},blockMath:{...pureMarkdown.pureMarkdownRules.blockMath,react:(node,output,state)=>{const{TeX}=getDependencies();return jsxRuntimeExports.jsx(TeX,{children:node.content},state.key)}},math:{...pureMarkdown.pureMarkdownRules.math,react:(node,output,state)=>{const{TeX}=getDependencies();return jsxRuntimeExports.jsx(TeX,{children:node.content},state.key)}},unescapedDollar:{...pureMarkdown.pureMarkdownRules.unescapedDollar,react:(node,output,state)=>{return "$"}},link:{...pureMarkdown.pureMarkdownRules.link,react:function(node,output,state){const link=SimpleMarkdown__default.default.defaultRules.link.react(node,output,state);const href=link.props.href;let rel=null;const isKAUrl=href?href.match(/https?:\/\/[^/]*khanacademy.org|^\//):false;if(!isKAUrl){rel="noopener noreferrer";}const newProps={...link.props,target:"_blank",href,rel};if(state.baseElements&&state.baseElements.Link){return state.baseElements.Link(newProps)}return React__namespace.cloneElement(link,newProps)}},codeBlock:{...pureMarkdown.pureMarkdownRules.codeBlock,react:(node,output,state)=>{if(node.lang==="alt"){return jsxRuntimeExports.jsx("div",{className:"perseus-markdown-alt perseus-sr-only",children:output(node.content,state)},state.key)}return SimpleMarkdown__default.default.defaultRules.codeBlock.react(node,output,state)}},lint:{...pureMarkdown.pureMarkdownRules.lint,react:(node,output,state)=>{return jsxRuntimeExports.jsx(Lint,{message:node.message,ruleName:node.ruleName,inline:isInline(node.content),blockHighlight:node.blockHighlight,insideTable:node.insideTable,severity:node.severity,children:output(node.content,state)})}}};function isInline(node){return !!(node&&node.type&&inlineNodeTypes.hasOwnProperty(node.type))}const inlineNodeTypes={text:true,math:true,unescapedDollar:true,link:true,img:true,strong:true,u:true,em:true,del:true,code:true};const builtParser$1=SimpleMarkdown__default.default.parserFor(rules$1);const parse$3=(source,state)=>{const paragraphedSource=source+"\n\n";return builtParser$1(paragraphedSource,{...state,inline:false})};const inlineParser=(source,state)=>{return builtParser$1(source,{...state,inline:true})};const getContent=ast=>{if(___default.default.isArray(ast)){return ___default.default.flatten(___default.default.map(ast,getContent))}if(ast.content&&___default.default.isString(ast.content)){if(ast.type.toLowerCase().indexOf("code")!==-1){return ["",ast.content,""]}return [ast.content.replace(/\s+/g," ")]}const children=___default.default.chain(ast).values().flatten().filter(object=>object!=null&&___default.default.has(object,"type")).value();if(!children.length){return []}const nestedContent=getContent(children);if(ast.type==="paragraph"&&nestedContent.length){nestedContent[0]=nestedContent[0].replace(/^\s+/,"");const last=nestedContent.length-1;nestedContent[last]=nestedContent[last].replace(/\s+$/,"");}return nestedContent};const characterCount=source=>{const ast=parse$3(source);const content=getContent(ast).join("");return content.length};var PerseusMarkdown = {characterCount:characterCount,traverseContent:pureMarkdown.traverseContent,parse:parse$3,parseInline:inlineParser,reactFor:SimpleMarkdown__default.default.reactFor,ruleOutput:SimpleMarkdown__default.default.ruleOutput(rules$1,"react"),basicOutput:SimpleMarkdown__default.default.reactFor(SimpleMarkdown__default.default.ruleOutput(rules$1,"react")),sanitizeUrl:SimpleMarkdown__default.default.sanitizeUrl};
|
|
1675
1679
|
|
|
@@ -1709,13 +1713,13 @@ var widgets$1 = /*#__PURE__*/Object.freeze({
|
|
|
1709
1713
|
|
|
1710
1714
|
class WidgetContainer extends React__namespace.Component{componentDidMount(){if(this.state.widgetProps.apiOptions.isMobile){const containerWidth=ReactDOM__namespace.default.findDOMNode(this).offsetWidth;this.setState({sizeClass:getClassFromWidth(containerWidth)});}}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.type!==nextProps.type){throw new Error("WidgetContainer can't change widget type; set a different "+"key instead to recreate the container.")}}shouldComponentUpdate(nextProps,nextState){return this.props.shouldHighlight!==nextProps.shouldHighlight||this.props.type!==nextProps.type||this.state.widgetProps!==nextState.widgetProps||this.state.sizeClass!==nextState.sizeClass}render(){let className=classNames__default.default({"perseus-widget-container":true,"widget-highlight":this.props.shouldHighlight,"widget-nohighlight":!this.props.shouldHighlight,"perseus-widget__definition":this.props.type==="definition"});const type=this.props.type;const userAgent=navigator.userAgent;const WidgetType=getWidget(type);if(WidgetType==null){console.warn(`Widget type '${type}' not found!`);return jsxRuntimeExports.jsx("div",{className:className})}let subType="null";if(type==="interactive-graph"){const props=this.state.widgetProps;subType=props.graph?.type??"null";}let alignment=this.state.widgetProps.alignment;if(alignment==="default"){alignment=perseusCore.CoreWidgetRegistry.getDefaultAlignment(type);}className+=" widget-"+alignment;const apiOptions=this.state.widgetProps.apiOptions;const isStatic=this.state.widgetProps.static||apiOptions.readOnly;const staticContainerStyles={position:"relative",overflow:"visible"};const staticOverlayStyles={width:"100%",height:"100%",position:"absolute",top:0,left:0,zIndex:3};const linterContext=isLintable(type)?this.props.linterContext:{...this.props.linterContext,highlightLint:false};return jsxRuntimeExports.jsx("div",{className:className,style:isStatic?staticContainerStyles:{},children:jsxRuntimeExports.jsx(DependenciesContext.Consumer,{children:({analytics})=>jsxRuntimeExports.jsxs(ErrorBoundary,{metadata:{widget_type:type,widget_id:this.props.id},onError:error=>{analytics.onAnalyticsEvent({type:"perseus:widget-rendering-error:ti",payload:{widgetSubType:subType,widgetType:type,widgetId:this.props.id,message:error.message,userAgent:userAgent}});},children:[jsxRuntimeExports.jsx(WidgetType,{...this.state.widgetProps,linterContext:linterContext,containerSizeClass:this.state.sizeClass,ref:this.widgetRef}),isStatic&&jsxRuntimeExports.jsx("div",{style:staticOverlayStyles})]})})})}constructor(...args){super(...args),this.widgetRef=React__namespace.createRef(),this.state={sizeClass:containerSizeClass.MEDIUM,widgetProps:this.props.initialProps},this.getWidget=()=>{return this.widgetRef.current},this.replaceWidgetProps=newWidgetProps=>{this.setState({widgetProps:newWidgetProps});};}}WidgetContainer.defaultProps={linterContext:PerseusLinter.linterContextDefault};
|
|
1711
1715
|
|
|
1712
|
-
const rContainsNonWhitespace=/\S/;const rImageURL=/(web\+graphie|https):\/\/[^\s]*/;const noopOnRender=()=>{};const makeContainerId=id=>"container:"+id;const isIdPathPrefix=function(prefixArray,wholeArray){if(prefixArray===null||wholeArray===null){return prefixArray===wholeArray}return ___default.default.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return ___default.default.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return perseusCore.splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:perseusCore.getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!___default.default.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.handleRender({});this._currentFocus=null;this.props.initializeUserInput?.(this.props.widgets,this.props.problemNum??0);if(this.props.serializedState){this.restoreSerializedState(this.props.serializedState);}if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}UNSAFE_componentWillReceiveProps(nextProps){if(isDifferentQuestion(this.props,nextProps)){this.props.initializeUserInput?.(nextProps.widgets,nextProps.problemNum??0);this.setState(this._getInitialWidgetState(nextProps));}}shouldComponentUpdate(nextProps,nextState){if(this.props.alwaysUpdate){return true}const stateChanged=!___default.default.isEqual(this.state,nextState);const propsChanged=!___default.default.isEqual(this.props,nextProps);return propsChanged||stateChanged}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&&___default.default.isEqual(this.state.translationLintErrors,nextState.translationLintErrors)&&(!this.props.linterContext.highlightLint||___default.default.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&&!___default.default.isEqual(this.props.serializedState,prevProps.serializedState)){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,userInput:this.props.userInput?.[widgetId],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:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewModeRubric:reviewModeRubric,reviewMode:this.props.reviewMode,onChange:(newProps,cb,silent=false)=>{this._setWidgetProps(widgetId,newProps,cb,silent);},handleUserInput:newUserInput=>{const updatedUserInput={...this.props.userInput,[widgetId]:newUserInput};const emptyWidgetIds=perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,updatedUserInput,this.context.locale);const widgetsEmpty=emptyWidgetIds.length>0;this.props.handleUserInput?.(widgetId,newUserInput,widgetsEmpty);this.props.onInteractWithWidget(widgetId);},trackInteraction:interactionTracker.track,isLastUsedWidget:widgetId===this.state.lastUsedWidgetId}}emptyWidgets(){if(!this.props.userInput){throw new Error(`emptyWidgets called without providing userInput to Renderer`)}return perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale)}handleStateUpdate(id,cb,silent){this.setState(prevState=>{const lastUsedWidgetId=silent?prevState.lastUsedWidgetId:id;return {lastUsedWidgetId}},()=>{setTimeout(()=>{const cbResult=cb&&cb();if(!silent){this.props.onInteractWithWidget(id);}if(cbResult!==false){this._setCurrentFocus([id]);}},0);});}_setWidgetProps(id,nextWidgetProps,cb,silent){this.setState(prevState=>{const widgetProps=nextWidgetProps?{...prevState.widgetProps,[id]:{...prevState.widgetProps[id],...nextWidgetProps}}:prevState.widgetProps;return {widgetProps}},()=>{this.handleStateUpdate(id,cb,silent);});}getUserInput(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInput called without providing userInput to Renderer`)}return this.widgetIds.map(id=>{return userInput[id]})}getUserInputMap(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInputMap called without providing userInput to Renderer`)}return userInput}getPromptJSON(){const{content}=this.props;const widgetJSON={};this.widgetIds.forEach(id=>{const widget=this.getWidgetInstance(id);widgetJSON[id]=widget?.getPromptJSON?.()||{};});return {content,widgets:widgetJSON}}score(){if(!this.props.userInput){throw new Error(`score called without providing userInput to Renderer`)}const scores=perseusScore.scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=perseusScore.flattenScores(scores);return combinedScore}render(){const apiOptions=this.getApiOptions();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__namespace.runLinter(parsedMarkdown,fullLinterContext,true);this._translationLinter.applyLintErrors(parsedMarkdown,[...this.state.translationLintErrors,...this.props.legacyPerseusLint||[]]);}const markdownContents=this.outputMarkdown(parsedMarkdown,{baseElements:apiOptions.baseElements});const className=classNames__default.default({[ClassNames.RENDERER]:true,[ClassNames.RESPONSIVE_RENDERER]:true,[ClassNames.TWO_COLUMN_RENDERER]:this._isTwoColumn});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=perseusCore.applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo,widgetProps:this._getAllWidgetsStartProps(allWidgetInfo,props)}},this._getAllWidgetsStartProps=(allWidgetInfo,props)=>{const{apiOptions,problemNum}=props;const widgetsStartProps={};const{strings}=this.props;wonderStuffCore.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=___default.default.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__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.getSerializedState=widgetProps=>{return perseusCore.mapObject(widgetProps||this.state.widgetProps,(props,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return props})},this.restoreSerializedState=(serializedState,callback)=>{const serializedWidgetIds=___default.default.keys(serializedState);const widgetPropIds=___default.default.keys(this.state.widgetProps);if(serializedWidgetIds.length!==widgetPropIds.length||___default.default.intersection(serializedWidgetIds,widgetPropIds).length!==serializedWidgetIds.length){Log.error("Refusing to restore bad serialized state:",perseusCore.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();}};const restoredWidgetProps={};Object.entries(serializedState).forEach(([widgetId,props])=>{const widget=this.getWidgetInstance(widgetId);if(widget?.restoreSerializedState){++numCallbacks;const restoreResult=widget.restoreSerializedState(props,fireCallback);restoredWidgetProps[widgetId]={...this.state.widgetProps[widgetId],...restoreResult};}else {restoredWidgetProps[widgetId]=props;}});this.props.restoreUserInputFromSerializedState?.(serializedState,this.props.widgets);this.setState({widgetProps:restoredWidgetProps},()=>{setTimeout(fireCallback,0);});},this.findInternalWidgets=filterCriterion=>{let filterFunc;if(typeof filterCriterion==="string"){if(filterCriterion.indexOf(" ")!==-1){const widgetId=filterCriterion;filterFunc=(id,widgetInfo,widget)=>id===widgetId;}else {const widgetType=filterCriterion;filterFunc=(id,widgetInfo,widget)=>{return widgetInfo.type===widgetType};}}else {filterFunc=filterCriterion;}const results=this.widgetIds.filter(id=>{const widgetInfo=this._getWidgetInfo(id);const widget=this.getWidgetInstance(id);return filterFunc(id,widgetInfo,widget)}).map(this.getWidgetInstance);return results},this.findWidgets=filterCriterion=>{return [...this.findInternalWidgets(filterCriterion),...this.props.findExternalWidgets(filterCriterion)]},this.getWidgetInstance=id=>{const ref=this._widgetContainers.get(makeContainerId(id));if(!ref){return null}return ref.getWidget()},this._onWidgetFocus=(id,focusPath=[])=>{if(!___default.default.isArray(focusPath)){throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),perseusCore.Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!___default.default.isEqual(fullPath,blurringFocusPath)){return}___default.default.defer(()=>{if(___default.default.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.getContent=(props,state)=>{return state.jiptContent||props.content},this.shouldRenderJiptPlaceholder=(props,state)=>{return getDependencies().JIPT.useJIPT&&state.jiptContent==null&&props.content.indexOf("crwdns")!==-1},this.replaceJiptContent=(content,paragraphIndex)=>{if(paragraphIndex==null){this.setState({jiptContent:content});}else {const codeFenceRegex=/^\s*(`{3,}|~{3,})\s*(\S+)?\s*\n([\s\S]+?)\s*\1\s*$/;if(codeFenceRegex.test(content));else if(/\S\n\s*\n\S/.test(content)){content="$\\large{\\red{\\text{Please translate each "+"paragraph to a single paragraph.}}}$";}else if(/^\s*$/.test(content)){content="$\\large{\\red{\\text{Translated paragraph is "+"currently empty}}}$";}const allContent=this.getContent(this.props,this.state);const paragraphs=JiptParagraphs.parseToArray(allContent);paragraphs[paragraphIndex]=content;this.setState({jiptContent:JiptParagraphs.joinFromArray(paragraphs)});}},this.outputMarkdown=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;state.paragraphIndex=i;const nodeOut=this.outputMarkdown(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}this._foundTextNodes=false;state.foundFullWidth=false;const output=this.outputNested(ast,state);let className;if(this.translationIndex!=null){className=null;}else {className=classNames__default.default({"perseus-paragraph-centered":!this._foundTextNodes,"perseus-paragraph-full-width":state.foundFullWidth&&ast.content.length===1});}return jsxRuntimeExports.jsx(QuestionParagraph,{className:className,translationIndex:this.translationIndex,paragraphIndex:state.paragraphIndex,inline:this.props.inline,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:output})},state.key)},this.outputNested=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;const nodeOut=this.outputNested(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}return this.outputNode(ast,this.outputNested,state)},this.outputNode=(node,nestedOutput,state)=>{const apiOptions=this.getApiOptions();const imagePlaceholder=apiOptions.imagePlaceholder;if(node.type==="widget"){const widgetPlaceholder=apiOptions.widgetPlaceholder;if(widgetPlaceholder){return widgetPlaceholder}this._foundTextNodes=true;if(this.widgetIds.includes(node.id)){return jsxRuntimeExports.jsx("span",{className:"renderer-widget-error",children:["Widget [[","☃"," ",node.id,"]] already exists."].join("")},state.key)}this.widgetIds.push(node.id);return this.renderWidget(node.widgetType,node.id,state)}if(node.type==="blockMath"){const content=preprocessTex(node.content);const innerStyle={overflowX:"auto",overflowY:"hidden",paddingTop:10,paddingBottom:10,marginTop:-10,marginBottom:-10};if(apiOptions.isMobile){const margin=16;const outerStyle={marginLeft:-16,marginRight:-16};const horizontalPadding={paddingLeft:margin,paddingRight:margin};const mobileInnerStyle={...innerStyle,...styles$G.mobileZoomableParentFix};return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",style:outerStyle,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:{...mobileInnerStyle,...horizontalPadding},children:jsxRuntimeExports.jsx(ZoomableTeX,{children:content})})})},state.key)}return jsxRuntimeExports.jsx("div",{className:"perseus-block-math",children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx("div",{className:"perseus-block-math-inner",style:innerStyle,children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{setAssetStatus:setAssetStatus,children:content})})})})},state.key)}if(node.type==="math"){const tex=node.content;return jsxRuntimeExports.jsx("span",{style:{whiteSpace:"nowrap"},children:jsxRuntimeExports.jsxs(ErrorBoundary,{children:[jsxRuntimeExports.jsx("span",{}),jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(Tex,{onRender:this.props.onRender,setAssetStatus:setAssetStatus,children:tex})}),jsxRuntimeExports.jsx("span",{})]})},state.key)}if(node.type==="image"){if(imagePlaceholder){return imagePlaceholder}const extraAttrs=___default.default.has(this.props.images,node.target)?this.props.images[node.target]:null;const responsive=!state.inTable;return jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{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$G.mobileZoomableParentFix};const wrappedOutput=jsxRuntimeExports.jsx("div",{style:{...mobileInnerStyle,overflowX:"auto"},children:jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(Zoomable,{animateHeight:true,children:output})})});return jsxRuntimeExports.jsx("div",{style:outerStyle,children:wrappedOutput})}return jsxRuntimeExports.jsx(ErrorBoundary,{children:PerseusMarkdown.ruleOutput(node,nestedOutput,state)},state.key)},this.handleRender=prevProps=>{const onRender=this.props.onRender;const oldOnRender=prevProps.onRender;if(onRender!==noopOnRender||oldOnRender!==noopOnRender){const $images=$__default.default(ReactDOM__namespace.default.findDOMNode(this)).find("img");if(oldOnRender!==noopOnRender){$images.off("load",oldOnRender);}if(onRender!==noopOnRender){$images.on("load",onRender);}}onRender();},this._setCurrentFocus=path=>{const apiOptions=this.getApiOptions();if(!isIdPathPrefix(path,this._currentFocus)){const prevFocus=this._currentFocus;if(prevFocus){this.blurPath(prevFocus);}this._currentFocus=path;apiOptions.onFocusChange(this._currentFocus,prevFocus);}},this.focus=()=>{let id;let focusResult;for(let i=0;i<this.widgetIds.length;i++){const widgetId=this.widgetIds[i];const widget=this.getWidgetInstance(widgetId);const widgetFocusResult=widget?.focus?.();if(widgetFocusResult){id=widgetId;focusResult=widgetFocusResult;break}}if(id){let path;if(typeof focusResult==="object"){path=[id].concat(focusResult.path||[]);Log.error("Renderer received a focus result of type 'object' "+"instead of the expected type 'boolean'",perseusCore.Errors.Internal,{loggedMetadata:{focusResult:JSON.stringify(focusResult),currentProps:JSON.stringify(this.state.widgetProps)}});}else {path=[id];}this._setCurrentFocus(path);return true}},this.getDOMNodeForPath=path=>{const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){return ReactDOM__namespace.default.findDOMNode(widget)}},this.getInputPaths=()=>{const inputPaths=[];this.widgetIds.forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getInputPaths){const widgetInputPaths=widget.getInputPaths();widgetInputPaths.forEach(inputPath=>{const relativeInputPath=[widgetId].concat(inputPath);inputPaths.push(relativeInputPath);});}});return inputPaths},this.focusPath=path=>{if(___default.default.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!___default.default.isEqual(this._currentFocus,path)){return}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget){const blurWidget=this.getWidgetInstance(widgetId);blurWidget?.blurInputPath?.(interWidgetPath);}},this.blur=()=>{if(this._currentFocus){this.blurPath(this._currentFocus);}},this.serialize=()=>{const state={};___default.default.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!___default.default.isEmpty(s)){state[id]=s;}},this);return state},this.getWidgetIds=()=>{return this.widgetIds},this.handletranslationLintErrors=lintErrors=>{if(!this._isMounted){return}this.setState({translationLintErrors:lintErrors});};this._translationLinter=new TranslationLinter;this.state={jiptContent:null,translationLintErrors:[],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,linterContext:PerseusLinter__namespace.linterContextDefault};const styles$G={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
|
|
1716
|
+
const rContainsNonWhitespace=/\S/;const rImageURL=/(web\+graphie|https):\/\/[^\s]*/;const noopOnRender=()=>{};const makeContainerId=id=>"container:"+id;const isIdPathPrefix=function(prefixArray,wholeArray){if(prefixArray===null||wholeArray===null){return prefixArray===wholeArray}return ___default.default.every(prefixArray,(elem,i)=>{if(wholeArray!=null){return ___default.default.isEqual(elem,wholeArray[i])}})};function isDifferentQuestion(propsA,propsB){function makeItem(props){return perseusCore.splitPerseusItem({question:{content:props.content,widgets:props.widgets,images:{}},hints:[],answerArea:perseusCore.getDefaultAnswerArea()})}return propsA.problemNum!==propsB.problemNum||!___default.default.isEqual(makeItem(propsA),makeItem(propsB))}class Renderer extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.handleRender({});this._currentFocus=null;this.props.initializeUserInput?.(this.props.widgets,this.props.problemNum??0);if(this.props.serializedState){this.restoreSerializedState(this.props.serializedState);}if(this.props.linterContext.highlightLint){this._translationLinter.runLinter(this.props.content,this.handletranslationLintErrors);}}UNSAFE_componentWillReceiveProps(nextProps){if(isDifferentQuestion(this.props,nextProps)){this.props.initializeUserInput?.(nextProps.widgets,nextProps.problemNum??0);this.setState(this._getInitialWidgetState(nextProps));}}shouldComponentUpdate(nextProps,nextState){if(this.props.alwaysUpdate){return true}const stateChanged=!___default.default.isEqual(this.state,nextState);const propsChanged=!___default.default.isEqual(this.props,nextProps);return propsChanged||stateChanged}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&&___default.default.isEqual(this.state.translationLintErrors,nextState.translationLintErrors)&&(!this.props.linterContext.highlightLint||___default.default.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&&!___default.default.isEqual(this.props.serializedState,prevProps.serializedState)){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,userInput:this.props.userInput?.[widgetId],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:___default.default.partial(this._onWidgetFocus,widgetId),onBlur:___default.default.partial(this._onWidgetBlur,widgetId),findWidgets:this.findWidgets,reviewModeRubric:reviewModeRubric,reviewMode:this.props.reviewMode,onChange:(newProps,cb,silent=false)=>{this._setWidgetProps(widgetId,newProps,cb,silent);},handleUserInput:newUserInput=>{const updatedUserInput={...this.props.userInput,[widgetId]:newUserInput};const emptyWidgetIds=perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,updatedUserInput,this.context.locale);const widgetsEmpty=emptyWidgetIds.length>0;this.props.handleUserInput?.(widgetId,newUserInput,widgetsEmpty);this.props.onInteractWithWidget(widgetId);},trackInteraction:interactionTracker.track,isLastUsedWidget:widgetId===this.state.lastUsedWidgetId}}emptyWidgets(){if(!this.props.userInput){throw new Error(`emptyWidgets called without providing userInput to Renderer`)}return perseusScore.emptyWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale)}handleStateUpdate(id,cb,silent){this.setState(prevState=>{const lastUsedWidgetId=silent?prevState.lastUsedWidgetId:id;return {lastUsedWidgetId}},()=>{setTimeout(()=>{const cbResult=cb&&cb();if(!silent){this.props.onInteractWithWidget(id);}if(cbResult!==false){this._setCurrentFocus([id]);}},0);});}_setWidgetProps(id,nextWidgetProps,cb,silent){this.setState(prevState=>{const widgetProps=nextWidgetProps?{...prevState.widgetProps,[id]:{...prevState.widgetProps[id],...nextWidgetProps}}:prevState.widgetProps;return {widgetProps}},()=>{this.handleStateUpdate(id,cb,silent);});}getUserInput(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInput called without providing userInput to Renderer`)}return this.widgetIds.map(id=>{return userInput[id]})}getUserInputMap(){const userInput=this.props.userInput;if(!userInput){throw new Error(`getUserInputMap called without providing userInput to Renderer`)}return userInput}getPromptJSON(){const{content}=this.props;const widgetJSON={};this.widgetIds.forEach(id=>{const widget=this.getWidgetInstance(id);widgetJSON[id]=widget?.getPromptJSON?.()||{};});return {content,widgets:widgetJSON}}score(){if(!this.props.userInput){throw new Error(`score called without providing userInput to Renderer`)}const scores=perseusScore.scoreWidgetsFunctional(this.state.widgetInfo,this.widgetIds,this.props.userInput,this.context.locale);const combinedScore=perseusScore.flattenScores(scores);return combinedScore}render(){const apiOptions=this.getApiOptions();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__namespace.runLinter(parsedMarkdown,fullLinterContext,true);this._translationLinter.applyLintErrors(parsedMarkdown,[...this.state.translationLintErrors,...this.props.legacyPerseusLint||[]]);}const markdownContents=this.outputMarkdown(parsedMarkdown,{baseElements:apiOptions.baseElements});const className=classNames__default.default({[ClassNames.RENDERER]:true,[ClassNames.RESPONSIVE_RENDERER]:true,[ClassNames.TWO_COLUMN_RENDERER]:this._isTwoColumn});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=perseusCore.applyDefaultsToWidgets(props.widgets);return {widgetInfo:allWidgetInfo,widgetProps:this._getAllWidgetsStartProps(allWidgetInfo,props)}},this._getAllWidgetsStartProps=(allWidgetInfo,props)=>{const{apiOptions,problemNum}=props;const widgetsStartProps={};const{strings}=this.props;wonderStuffCore.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=___default.default.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__namespace.pushContextStack(this.props.linterContext,"widget")},makeContainerId(id))}return null},this.getSerializedState=widgetProps=>{return perseusCore.mapObject(widgetProps||this.state.widgetProps,(props,widgetId)=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getSerializedState){return excludeDenylistKeys(widget.getSerializedState())}return props})},this.restoreSerializedState=(serializedState,callback)=>{const serializedWidgetIds=___default.default.keys(serializedState);const widgetPropIds=___default.default.keys(this.state.widgetProps);if(serializedWidgetIds.length!==widgetPropIds.length||___default.default.intersection(serializedWidgetIds,widgetPropIds).length!==serializedWidgetIds.length){Log.error("Refusing to restore bad serialized state:",perseusCore.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();}};const restoredWidgetProps={};Object.entries(serializedState).forEach(([widgetId,props])=>{const widget=this.getWidgetInstance(widgetId);if(widget?.restoreSerializedState){++numCallbacks;const restoreResult=widget.restoreSerializedState(props,fireCallback);restoredWidgetProps[widgetId]={...this.state.widgetProps[widgetId],...restoreResult};}else {restoredWidgetProps[widgetId]=props;}});this.props.restoreUserInputFromSerializedState?.(serializedState,this.props.widgets);this.setState({widgetProps:restoredWidgetProps},()=>{setTimeout(fireCallback,0);});},this.findInternalWidgets=filterCriterion=>{let filterFunc;if(typeof filterCriterion==="string"){if(filterCriterion.indexOf(" ")!==-1){const widgetId=filterCriterion;filterFunc=(id,widgetInfo,widget)=>id===widgetId;}else {const widgetType=filterCriterion;filterFunc=(id,widgetInfo,widget)=>{return widgetInfo.type===widgetType};}}else {filterFunc=filterCriterion;}const results=this.widgetIds.filter(id=>{const widgetInfo=this._getWidgetInfo(id);const widget=this.getWidgetInstance(id);return filterFunc(id,widgetInfo,widget)}).map(this.getWidgetInstance);return results},this.findWidgets=filterCriterion=>{return [...this.findInternalWidgets(filterCriterion),...this.props.findExternalWidgets(filterCriterion)]},this.getWidgetInstance=id=>{const ref=this._widgetContainers.get(makeContainerId(id));if(!ref){return null}return ref.getWidget()},this._onWidgetFocus=(id,focusPath=[])=>{if(!___default.default.isArray(focusPath)){throw new perseusCore.PerseusError("widget props.onFocus focusPath must be an Array, "+"but was"+JSON.stringify(focusPath),perseusCore.Errors.Internal)}this._setCurrentFocus([id].concat(focusPath));},this._onWidgetBlur=(id,blurPath)=>{const blurringFocusPath=this._currentFocus;const fullPath=[id].concat(blurPath);if(!___default.default.isEqual(fullPath,blurringFocusPath)){return}___default.default.defer(()=>{if(___default.default.isEqual(this._currentFocus,blurringFocusPath)){this._setCurrentFocus(null);}});},this.getContent=(props,state)=>{return state.jiptContent||props.content},this.shouldRenderJiptPlaceholder=(props,state)=>{return getDependencies().JIPT.useJIPT&&state.jiptContent==null&&props.content.indexOf("crwdns")!==-1},this.replaceJiptContent=(content,paragraphIndex)=>{if(paragraphIndex==null){this.setState({jiptContent:content});}else {const codeFenceRegex=/^\s*(`{3,}|~{3,})\s*(\S+)?\s*\n([\s\S]+?)\s*\1\s*$/;if(codeFenceRegex.test(content));else if(/\S\n\s*\n\S/.test(content)){content="$\\large{\\red{\\text{Please translate each "+"paragraph to a single paragraph.}}}$";}else if(/^\s*$/.test(content)){content="$\\large{\\red{\\text{Translated paragraph is "+"currently empty}}}$";}const allContent=this.getContent(this.props,this.state);const paragraphs=JiptParagraphs.parseToArray(allContent);paragraphs[paragraphIndex]=content;this.setState({jiptContent:JiptParagraphs.joinFromArray(paragraphs)});}},this.outputMarkdown=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;state.paragraphIndex=i;const nodeOut=this.outputMarkdown(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}this._foundTextNodes=false;state.foundFullWidth=false;const output=this.outputNested(ast,state);let className;if(this.translationIndex!=null){className=null;}else {className=classNames__default.default({"perseus-paragraph-centered":!this._foundTextNodes,"perseus-paragraph-full-width":state.foundFullWidth&&ast.content.length===1});}return jsxRuntimeExports.jsx(QuestionParagraph,{className:className,translationIndex:this.translationIndex,paragraphIndex:state.paragraphIndex,inline:this.props.inline,children:jsxRuntimeExports.jsx(ErrorBoundary,{children:output})},state.key)},this.outputNested=(ast,state)=>{if(___default.default.isArray(ast)){const oldKey=state.key;const result=[];let lastWasString=false;for(let i=0;i<ast.length;i++){state.key=i;const nodeOut=this.outputNested(ast[i],state);const isString=typeof nodeOut==="string";if(typeof nodeOut==="string"&&lastWasString){result[result.length-1]+=nodeOut;}else {result.push(nodeOut);}lastWasString=isString;}state.key=oldKey;return result}return this.outputNode(ast,this.outputNested,state)},this.outputNode=(node,nestedOutput,state)=>{const apiOptions=this.getApiOptions();const imagePlaceholder=apiOptions.imagePlaceholder;if(node.type==="widget"){const widgetPlaceholder=apiOptions.widgetPlaceholder;if(widgetPlaceholder){return widgetPlaceholder}this._foundTextNodes=true;if(this.widgetIds.includes(node.id)){return jsxRuntimeExports.jsx("span",{className:"renderer-widget-error",children:["Widget [[","☃"," ",node.id,"]] already exists."].join("")},state.key)}this.widgetIds.push(node.id);return this.renderWidget(node.widgetType,node.id,state)}if(node.type==="blockMath"){const content=preprocessTex(node.content);const innerStyle={overflowX:"auto",overflowY:"hidden",paddingTop:10,paddingBottom:10,marginTop:-10,marginBottom:-10};if(apiOptions.isMobile){const margin=16;const outerStyle={marginLeft:-16,marginRight:-16};const horizontalPadding={paddingLeft:margin,paddingRight:margin};const mobileInnerStyle={...innerStyle,...styles$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=___default.default.has(this.props.images,node.target)?this.props.images[node.target]:null;const responsive=!state.inTable;return jsxRuntimeExports.jsx(ErrorBoundary,{children:jsxRuntimeExports.jsx(context$1.Consumer,{children:({setAssetStatus})=>jsxRuntimeExports.jsx(SvgImage,{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=$__default.default(ReactDOM__namespace.default.findDOMNode(this)).find("img");if(oldOnRender!==noopOnRender){$images.off("load",oldOnRender);}if(onRender!==noopOnRender){$images.on("load",onRender);}}onRender();},this._setCurrentFocus=path=>{const apiOptions=this.getApiOptions();if(!isIdPathPrefix(path,this._currentFocus)){const prevFocus=this._currentFocus;if(prevFocus){this.blurPath(prevFocus);}this._currentFocus=path;apiOptions.onFocusChange(this._currentFocus,prevFocus);}},this.focus=()=>{let id;let focusResult;for(let i=0;i<this.widgetIds.length;i++){const widgetId=this.widgetIds[i];const widget=this.getWidgetInstance(widgetId);const widgetFocusResult=widget?.focus?.();if(widgetFocusResult){id=widgetId;focusResult=widgetFocusResult;break}}if(id){let path;if(typeof focusResult==="object"){path=[id].concat(focusResult.path||[]);Log.error("Renderer received a focus result of type 'object' "+"instead of the expected type 'boolean'",perseusCore.Errors.Internal,{loggedMetadata:{focusResult:JSON.stringify(focusResult),currentProps:JSON.stringify(this.state.widgetProps)}});}else {path=[id];}this._setCurrentFocus(path);return true}},this.getDOMNodeForPath=path=>{const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget?.getDOMNodeForPath){return widget.getDOMNodeForPath(interWidgetPath)}if(interWidgetPath.length===0){return ReactDOM__namespace.default.findDOMNode(widget)}},this.getInputPaths=()=>{const inputPaths=[];this.widgetIds.forEach(widgetId=>{const widget=this.getWidgetInstance(widgetId);if(widget&&widget.getInputPaths){const widgetInputPaths=widget.getInputPaths();widgetInputPaths.forEach(inputPath=>{const relativeInputPath=[widgetId].concat(inputPath);inputPaths.push(relativeInputPath);});}});return inputPaths},this.focusPath=path=>{if(___default.default.isEqual(this._currentFocus,path)){return}if(this._currentFocus){this.blurPath(this._currentFocus);}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const focusWidget=this.getWidgetInstance(widgetId);focusWidget?.focusInputPath?.(interWidgetPath);},this.blurPath=path=>{if(!___default.default.isEqual(this._currentFocus,path)){return}const widgetId=___default.default.first(path);const interWidgetPath=___default.default.rest(path);const widget=this.getWidgetInstance(widgetId);if(widget){const blurWidget=this.getWidgetInstance(widgetId);blurWidget?.blurInputPath?.(interWidgetPath);}},this.blur=()=>{if(this._currentFocus){this.blurPath(this._currentFocus);}},this.serialize=()=>{const state={};___default.default.each(this.state.widgetInfo,function(info,id){const widget=this.getWidgetInstance(id);const s=widget.serialize();if(!___default.default.isEmpty(s)){state[id]=s;}},this);return state},this.getWidgetIds=()=>{return this.widgetIds},this.handletranslationLintErrors=lintErrors=>{if(!this._isMounted){return}this.setState({translationLintErrors:lintErrors});};this._translationLinter=new TranslationLinter;this.state={jiptContent:null,translationLintErrors:[],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,linterContext:PerseusLinter__namespace.linterContextDefault};const styles$E={mobileZoomableParentFix:{transform:"translate3d(0,0,0)"}};
|
|
1713
1717
|
|
|
1714
|
-
const{captureScratchpadTouchStart: captureScratchpadTouchStart$
|
|
1715
|
-
${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$
|
|
1718
|
+
const{captureScratchpadTouchStart: captureScratchpadTouchStart$2}=Util;const InputWithExamples=React.forwardRef(function InputWithExamples({shouldShowExamples=true,onFocus=()=>{},onBlur=()=>{},disabled=false,linterContext=PerseusLinter__namespace.linterContextDefault,className="",...props},ref){const context=React__namespace.useContext(PerseusI18nContext);const inputRef=React__namespace.useRef(null);const[inputFocused,setInputFocused]=React__namespace.useState(false);const id=React.useId();const ariaId=`aria-for-${id}`;React.useImperativeHandle(ref,()=>({current:inputRef.current,focus:()=>{if(inputRef.current){inputRef.current.focus();}},blur:()=>{if(inputRef.current){inputRef.current.blur();}}}));const getInputClassName=()=>{let inputClassName=ClassNames.INPUT;if(inputFocused){inputClassName+=" "+ClassNames.FOCUSED;}if(className){inputClassName+=" "+className;}return inputClassName};const handleFocus=()=>{onFocus();setInputFocused(true);};const handleBlur=()=>{onBlur();setInputFocused(false);};const renderInput=()=>{const examplesAria=shouldShowExamples?`${props.examples[0]}
|
|
1719
|
+
${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$2,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off",spellCheck:"false"};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(TextInput,{...inputProps}),jsxRuntimeExports.jsx("span",{id:ariaId,style:{display:"none"},children:examplesAria})]})};const renderTooltipContent=()=>{return jsxRuntimeExports.jsx(Tooltip.TooltipContent,{children:jsxRuntimeExports.jsx("div",{id:id,className:"input-with-examples-tooltip",children:jsxRuntimeExports.jsx(Renderer,{content:examplesContent,linterContext:PerseusLinter__namespace.pushContextStack(linterContext,"input-with-examples"),strings:context.strings})})})};const examplesContent=props.examples.length<=2?props.examples.join(" "):props.examples.map((example,index)=>{return index===0&&example.startsWith("**")?`${example}
|
|
1716
1720
|
`:`- ${example}`}).join("\n");const showExamplesTooltip=shouldShowExamples&&inputFocused;return jsxRuntimeExports.jsx(Tooltip__default.default,{content:renderTooltipContent(),opened:showExamplesTooltip,placement:"bottom",children:renderInput()})});
|
|
1717
1721
|
|
|
1718
|
-
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__namespace.Component{getPromptJSON(){return getPromptJSON$s(this.props)}examples(){const{strings}=this.context;const type=this.props.answerType;const forms=perseusScore.inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);const examples=forms.map(form=>formExamples[form](this.props,strings));return [strings.yourAnswer].concat(examples)}getSerializedState(){
|
|
1722
|
+
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__namespace.Component{getPromptJSON(){return getPromptJSON$s(this.props)}examples(){const{strings}=this.context;const type=this.props.answerType;const forms=perseusScore.inputNumberAnswerTypes[type].forms.split(/\s*,\s*/);const examples=forms.map(form=>formExamples[form](this.props,strings));return [strings.yourAnswer].concat(examples)}getSerializedState(){return {alignment:this.props.alignment,static:this.props.static,simplify:this.props.simplify,size:this.props.size,answerType:this.props.answerType,rightAlign:this.props.rightAlign,currentValue:this.props.userInput.currentValue}}render(){if(this.props.apiOptions.customKeypad){const input=jsxRuntimeExports.jsx(SimpleKeypadInput,{ref:"input",value:this.props.userInput.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.userInput.currentValue){inputStyles.push(styles$D.answerStateUnanswered);}return jsxRuntimeExports.jsx(InputWithExamples,{ref:"input",value:this.props.userInput.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.handleUserInput({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 [[]]};}}InputNumber.contextType=PerseusI18nContext;InputNumber.defaultProps={size:"normal",answerType:"number",rightAlign:false,apiOptions:ApiOptions.defaults,linterContext:PerseusLinter.linterContextDefault,userInput:{currentValue:""}};const styles$D=aphrodite.StyleSheet.create({default:{width:80,height:"auto",direction:"ltr"},small:{width:40},leftAlign:{paddingLeft:wonderBlocksTokens.spacing.xxxSmall_4,paddingRight:0},rightAlign:{textAlign:"right",paddingLeft:0,paddingRight:wonderBlocksTokens.spacing.xxxSmall_4},answerStateUnanswered:{backgroundColor:"#eee",border:"solid 1px #999"}});function getOneCorrectAnswerFromRubric(rubric){if(rubric.value==null){return}let answerString=String(rubric.value);if(rubric.inexact&&rubric.maxError){answerString+=" ± "+rubric.maxError;}return answerString}function getUserInputFromSerializedState$h(serializedState){return {currentValue:serializedState.currentValue}}function getStartUserInput$i(){return {currentValue:""}}var InputNumber$1 = {name:"input-number",displayName:"Input number (deprecated - use numeric input instead)",hidden:true,widget:InputNumber,isLintable:true,getOneCorrectAnswerFromRubric,getStartUserInput: getStartUserInput$i,getUserInputFromSerializedState: getUserInputFromSerializedState$h};
|
|
1719
1723
|
|
|
1720
1724
|
const getPromptJSON$r=renderProps=>{return {type:"numeric-input",label:renderProps.labelText,userInput:{value:renderProps.userInput.currentValue}}};
|
|
1721
1725
|
|
|
@@ -1727,33 +1731,25 @@ class NumericInput extends React__namespace.Component{getPromptJSON(){return get
|
|
|
1727
1731
|
|
|
1728
1732
|
const getPromptJSON$q=(renderProps,userInput)=>{const choices=renderProps.choices||[];const options=choices.map(choice=>{const option={value:choice.content};if(choice.rationale){option.rationale=choice.rationale;}return option});return {type:"radio",hasNoneOfTheAbove:!!renderProps.hasNoneOfTheAbove,options,userInput:{selectedOptions:userInput?.choicesSelected?.slice()??[]}}};
|
|
1729
1733
|
|
|
1730
|
-
var styles$
|
|
1731
|
-
|
|
1732
|
-
const SCROLL_DISTANCE=100;function ScrollableView({overflowX,overflowY,children,className,scrollDescription,style,role="group",...additionalProps}){const{strings}=usePerseusI18n();const containerRef=React.useRef(null);const[isScrollable,setIsScrollable]=React.useState(false);const[canScrollStart,setCanScrollStart]=React.useState(false);const[canScrollEnd,setCanScrollEnd]=React.useState(false);const[isRtl,setIsRtl]=React.useState(false);const updateScrollState=React__namespace.useCallback(()=>{if(!containerRef.current){return}const{scrollLeft,scrollWidth,clientWidth}=containerRef.current;setIsRtl(getComputedStyle(containerRef.current).direction==="rtl");const scrollableThreshold=5;setIsScrollable(scrollWidth>clientWidth+scrollableThreshold);if(isRtl){setCanScrollStart(Math.abs(scrollLeft)<scrollWidth-clientWidth-scrollableThreshold);setCanScrollEnd(scrollLeft<-5);}else {setCanScrollStart(scrollLeft>scrollableThreshold);setCanScrollEnd(scrollLeft+clientWidth<scrollWidth-scrollableThreshold);}},[isRtl]);const scroll=direction=>{if(!containerRef.current){return}const scrollNegative=isRtl&&direction!=="start"||!isRtl&&direction==="start";const scrollAmount=scrollNegative?-100:SCROLL_DISTANCE;containerRef.current.scrollBy({left:scrollAmount,behavior:"smooth"});};React.useEffect(()=>{const container=containerRef.current;if(!container){return}updateScrollState();container.addEventListener("scroll",updateScrollState);window.addEventListener("resize",updateScrollState);return ()=>{container.removeEventListener("scroll",updateScrollState);window.removeEventListener("resize",updateScrollState);}},[children,updateScrollState]);const mergeStyle={overflowX:isScrollable&&overflowX==="auto"?"scroll":overflowX,overflowY:isScrollable&&overflowY==="auto"?"scroll":overflowY,scrollbarWidth:"thin",...style};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[canScrollEnd&&jsxRuntimeExports.jsx("div",{className:`${styles$E.scrollFade} ${isRtl?styles$E.scrollFadeRight:styles$E.scrollFadeLeft}`}),canScrollStart&&jsxRuntimeExports.jsx("div",{className:`${styles$E.scrollFade} ${isRtl?styles$E.scrollFadeLeft:styles$E.scrollFadeRight}`}),jsxRuntimeExports.jsx("div",{...additionalProps,role:role,className:className,style:mergeStyle,ref:containerRef,children:children}),isScrollable&&jsxRuntimeExports.jsx(ScrollButtons,{onScrollStart:()=>isRtl?scroll("end"):scroll("start"),onScrollEnd:()=>isRtl?scroll("start"):scroll("end"),canScrollStart:canScrollStart,canScrollEnd:canScrollEnd,scrollDescription:scrollDescription?scrollDescription:strings.scrollAnswers,isRTL:isRtl})]})}function ScrollButtons({onScrollStart,onScrollEnd,canScrollStart,canScrollEnd,scrollDescription,isRTL}){const{strings}=usePerseusI18n();return jsxRuntimeExports.jsxs("div",{className:styles$E.scrollButtonsContainer,children:[jsxRuntimeExports.jsx(IconButton__default.default,{icon:isRTL?caretRightIcon__default.default:caretLeftIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:isRTL?onScrollEnd:onScrollStart,"aria-label":strings.scrollStart,disabled:isRTL?!canScrollEnd:!canScrollStart}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:isRTL?caretLeftIcon__default.default:caretRightIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:isRTL?onScrollStart:onScrollEnd,"aria-label":strings.scrollEnd,disabled:isRTL?!canScrollStart:!canScrollEnd}),jsxRuntimeExports.jsx(wonderBlocksTypography.LabelSmall,{children:scrollDescription})]})}
|
|
1733
|
-
|
|
1734
|
-
if(typeof HTMLElement!=="undefined"&&!HTMLElement.prototype.scrollTo){HTMLElement.prototype.scrollTo=function(left,top){this.scrollLeft=left;this.scrollTop=top;};}const applyUniversalScrollOffset=(elementOrWindow,amount)=>{if(typeof elementOrWindow.scrollTo==="function"){elementOrWindow.scrollTo(0,amount);}else if("scrollTop"in elementOrWindow){elementOrWindow.scrollTop=amount;}};const scrollElementToOffset=(elementOrWindow,offset,duration=0,callback)=>{const startPosition=elementOrWindow===window?window.pageYOffset:elementOrWindow.scrollTop;const endPosition=offset;const scrollDistance=endPosition-startPosition;const tickLength=17;const numberOfSteps=duration/tickLength;let step=0;const scrollInterval=setInterval(function(){if(step<numberOfSteps){const x=step/numberOfSteps;const y=(-Math.cos(Math.PI*x)+1)/2;const newPosition=startPosition+scrollDistance*y;applyUniversalScrollOffset(elementOrWindow,newPosition);step+=1;}else {applyUniversalScrollOffset(elementOrWindow,endPosition);clearInterval(scrollInterval);}},tickLength);};const getScrollContainer=element=>{if(element===document.body){return window}if(element==null){return window}if(element.scrollHeight>element.clientHeight){return element}return getScrollContainer(element.parentElement)};const SCROLL_ANIMATION_DURATION=750;const scrollElementIntoView=(element,callback)=>{setTimeout(()=>{const scrollContainer=getScrollContainer(element);const childBounds=element.getBoundingClientRect();const containerBounds=scrollContainer===window?{top:0,bottom:window.innerHeight}:scrollContainer.getBoundingClientRect();let offset=0;const currentScrollTop=scrollContainer===window?window.scrollY:scrollContainer.scrollTop;if(childBounds.bottom>containerBounds.bottom){let distanceToScroll=childBounds.bottom-containerBounds.bottom;if(childBounds.top+distanceToScroll<containerBounds.top){distanceToScroll=childBounds.top-containerBounds.top;}offset=currentScrollTop+distanceToScroll;}else if(childBounds.top<containerBounds.top){const distanceToScroll=childBounds.top-containerBounds.top;offset=currentScrollTop+distanceToScroll;}scrollElementToOffset(scrollContainer,offset,SCROLL_ANIMATION_DURATION);},0);};
|
|
1735
|
-
|
|
1736
|
-
const{pureXsMax,pureSmMax,pureMdMin,pureMdMax,pureLgMin,pureLgMax,pureXlMin}=constants;var mediaQueries = {md:`@media screen and (min-width: ${pureMdMin}) and `+`(max-width: ${pureMdMax})`,xl:`@media screen and (min-width: ${pureXlMin})`,xsOrSmaller:`@media screen and (max-width: ${pureXsMax})`,smOrSmaller:`@media screen and (max-width: ${pureSmMax})`,mdOrSmaller:`@media screen and (max-width: ${pureMdMax})`,lgOrSmaller:`@media screen and (max-width: ${pureLgMax})`,lgOrLarger:`@media screen and (min-width: ${pureLgMin})`};
|
|
1734
|
+
var styles$C = {"scrollButtonsContainer":"perseus_kjDHiWdD"};
|
|
1737
1735
|
|
|
1738
|
-
const
|
|
1736
|
+
const SCROLL_DISTANCE=100;function ScrollableView({overflowX,overflowY,children,className,scrollDescription,style,role="group",...additionalProps}){const{strings}=usePerseusI18n();const containerRef=React.useRef(null);const[isScrollable,setIsScrollable]=React.useState(false);const[canScrollStart,setCanScrollStart]=React.useState(false);const[canScrollEnd,setCanScrollEnd]=React.useState(false);const[isRtl,setIsRtl]=React.useState(false);const updateScrollState=React__namespace.useCallback(()=>{if(!containerRef.current){return}const{scrollLeft,scrollWidth,clientWidth}=containerRef.current;setIsRtl(getComputedStyle(containerRef.current).direction==="rtl");const scrollableThreshold=5;setIsScrollable(scrollWidth>clientWidth+scrollableThreshold);if(isRtl){setCanScrollStart(Math.abs(scrollLeft)<scrollWidth-clientWidth-scrollableThreshold);setCanScrollEnd(scrollLeft<-5);}else {setCanScrollStart(scrollLeft>scrollableThreshold);setCanScrollEnd(scrollLeft+clientWidth<scrollWidth-scrollableThreshold);}},[isRtl]);const scroll=direction=>{if(!containerRef.current){return}const scrollNegative=isRtl&&direction!=="start"||!isRtl&&direction==="start";const scrollAmount=scrollNegative?-100:SCROLL_DISTANCE;containerRef.current.scrollBy({left:scrollAmount,behavior:"smooth"});};React.useEffect(()=>{const container=containerRef.current;if(!container){return}updateScrollState();container.addEventListener("scroll",updateScrollState);window.addEventListener("resize",updateScrollState);return ()=>{container.removeEventListener("scroll",updateScrollState);window.removeEventListener("resize",updateScrollState);}},[children,updateScrollState]);const mergeStyle={overflowX:isScrollable&&overflowX==="auto"?"scroll":overflowX,overflowY:isScrollable&&overflowY==="auto"?"scroll":overflowY,scrollbarWidth:"thin",...style};return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("div",{...additionalProps,role:role,className:className,style:mergeStyle,ref:containerRef,children:children}),isScrollable&&jsxRuntimeExports.jsx(ScrollButtons,{onScrollStart:()=>isRtl?scroll("end"):scroll("start"),onScrollEnd:()=>isRtl?scroll("start"):scroll("end"),canScrollStart:canScrollStart,canScrollEnd:canScrollEnd,scrollDescription:scrollDescription?scrollDescription:strings.scrollAnswers,isRTL:isRtl})]})}function ScrollButtons({onScrollStart,onScrollEnd,canScrollStart,canScrollEnd,scrollDescription,isRTL}){const{strings}=usePerseusI18n();return jsxRuntimeExports.jsxs("div",{className:styles$C.scrollButtonsContainer,children:[jsxRuntimeExports.jsx(IconButton__default.default,{icon:isRTL?caretRightIcon__default.default:caretLeftIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:isRTL?onScrollEnd:onScrollStart,"aria-label":strings.scrollStart,disabled:isRTL?!canScrollEnd:!canScrollStart}),jsxRuntimeExports.jsx(IconButton__default.default,{icon:isRTL?caretLeftIcon__default.default:caretRightIcon__default.default,actionType:"neutral",kind:"secondary",size:"small",onClick:isRTL?onScrollStart:onScrollEnd,"aria-label":strings.scrollEnd,disabled:isRTL?!canScrollStart:!canScrollEnd}),jsxRuntimeExports.jsx(wonderBlocksTypography.LabelSmall,{children:scrollDescription})]})}
|
|
1739
1737
|
|
|
1740
|
-
|
|
1738
|
+
var styles$B = {"base":"perseus_C4cWo-dY","is-correct":"perseus_vWc7XkhJ","isCorrect":"perseus_vWc7XkhJ","is-wrong":"perseus_yVmsF9sA","isWrong":"perseus_yVmsF9sA","icon":"perseus_brEUCVvd","circle-shape":"perseus_irgRpkgB","circleShape":"perseus_irgRpkgB","square-shape":"perseus_JsUZt48D","squareShape":"perseus_JsUZt48D"};
|
|
1741
1739
|
|
|
1742
|
-
const
|
|
1740
|
+
const Indicator=props=>{const{checked,showCorrectness}=props;const iconImage=checked&&showCorrectness==="correct"?checkIcon__default.default:checked&&showCorrectness==="wrong"?minusIcon__default.default:undefined;const icon=iconImage?jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{"aria-hidden":true,className:styles$B.icon,icon:iconImage,role:"img"}):undefined;const classes=[styles$B.base,styles$B[props.shape+"-shape"]];if(showCorrectness){classes.push(styles$B["is-"+showCorrectness]);}const handleClick=showCorrectness?undefined:event=>{event.stopPropagation();props.updateChecked(!checked);};return jsxRuntimeExports.jsxs("button",{"aria-pressed":checked,className:classes.join(" "),type:"button",ref:props.buttonRef,onClick:handleClick,children:[icon,props.content]})};
|
|
1743
1741
|
|
|
1744
|
-
|
|
1742
|
+
var styles$A = {"choice":"perseus_hm3uu-sq","is-correct":"perseus_qpU2z5U7","isCorrect":"perseus_qpU2z5U7","is-wrong":"perseus_dUXUrBDI","isWrong":"perseus_dUXUrBDI"};
|
|
1745
1743
|
|
|
1746
|
-
const
|
|
1744
|
+
const Choice$2=props=>{const showCorrectness=props.showCorrectness;const buttonRef=React.useRef(null);const indicatorShape=props.isMultiSelect?"square":"circle";const clickHandler=showCorrectness?undefined:()=>{buttonRef.current?.click();};const classes=[styles$A.choice].concat(showCorrectness?[styles$A["is-"+showCorrectness]]:[]).join(" ");return jsxRuntimeExports.jsxs("li",{className:classes,onClick:clickHandler,children:[jsxRuntimeExports.jsx(Indicator,{buttonRef:buttonRef,checked:props.checked,content:props.indicatorContent,shape:indicatorShape,showCorrectness:showCorrectness,updateChecked:props.updateChecked}),props.children]})};
|
|
1747
1745
|
|
|
1748
|
-
|
|
1746
|
+
var styles$z = {"container":"perseus_dzsult1u","choiceList":"perseus_HSvzOAAR","content":"perseus_A5d7KcQj","instructions":"perseus_skOlpdjN","rationale":"perseus_y4m8wyRd","isCorrect":"perseus_IfCbxIVP","reviewAnswers":"perseus_QYlQJ6BF"};
|
|
1749
1747
|
|
|
1750
|
-
|
|
1748
|
+
function getChoiceLetter(pos,strings){const lettersString=strings.letters;const letters=lettersString.split(" ");if(pos<letters.length){return letters[pos]}return " "}function getUserInputFromSerializedState$f(props,unshuffle=true){if(props.choiceStates){const choiceStates=props.choiceStates;const choicesSelected=choiceStates.map(()=>false);for(let i=0;i<choicesSelected.length;i++){const index=unshuffle?props.choices[i].originalIndex:i;choicesSelected[index]=choiceStates[i].selected;}return {choicesSelected}}const{values}=props;if(values){const choicesSelected=[...values];const valuesLength=values.length;for(let i=0;i<valuesLength;i++){const index=unshuffle?props.choices[i].originalIndex:i;choicesSelected[index]=values[i];}return {choicesSelected}}return {choicesSelected:props.choices.map(()=>false)}}
|
|
1751
1749
|
|
|
1752
|
-
const
|
|
1750
|
+
const getInstructionsText$1=({multipleSelect,countChoices,numCorrect,strings})=>{if(multipleSelect){if(perseusCore.usesNumCorrect(multipleSelect,!!countChoices,numCorrect)){return strings.chooseNumAnswers({numCorrect:String(numCorrect)})}return strings.chooseAllAnswers}return strings.chooseOneAnswer};
|
|
1753
1751
|
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
const{captureScratchpadTouchStart: captureScratchpadTouchStart$2}=Util;const MultipleChoiceComponent=({apiOptions,reviewModeRubric,reviewMode,editMode=false,multipleSelect=false,labelWrap,countChoices,numCorrect,isLastUsedWidget,choices,onChoiceChange})=>{const{strings}=usePerseusI18n();const choiceRefs=React.useRef([]);const prevReviewModeRubric=React.useRef();React.useEffect(()=>{if(apiOptions.canScrollPage&&isLastUsedWidget&&reviewModeRubric&&!prevReviewModeRubric.current){const checkedIndex=choices.findIndex(c=>c.checked);if(checkedIndex>=0){const ref=choiceRefs.current[checkedIndex];if(ref.current){scrollElementIntoView(ref.current);}}}prevReviewModeRubric.current=reviewModeRubric;},[apiOptions,isLastUsedWidget,reviewModeRubric,choices]);const choiceListClassName=classNames__default.default("perseus-widget-radio",!editMode&&"perseus-rendered-radio",styles$y.choiceList);const instructionsClassName=classNames__default.default(styles$y.instructions);const instructions=getInstructionsText$1({multipleSelect,countChoices,numCorrect,strings});const fieldset=jsxRuntimeExports.jsxs("fieldset",{className:`perseus-widget-radio-fieldset ${styles$y.responsiveFieldset}`,"data-feature-flag":"feature flag is ON",children:[jsxRuntimeExports.jsx("legend",{className:"perseus-sr-only",children:instructions}),jsxRuntimeExports.jsx("div",{className:instructionsClassName,"aria-hidden":"true",children:instructions}),jsxRuntimeExports.jsx(ScrollableView,{overflowX:"auto",children:jsxRuntimeExports.jsx("ul",{className:choiceListClassName,children:choices.map((choice,i)=>{let Element=Choice$2;const ref=React__namespace.createRef();choiceRefs.current[i]=ref;const elementProps={apiOptions:apiOptions,multipleSelect:multipleSelect,checked:choice.checked,previouslyAnswered:choice.previouslyAnswered,reviewMode,correct:choice.correct,rationale:choice.rationale,content:choice.content,disabled:apiOptions.readOnly||choice.disabled,showCorrectness:reviewMode||!!choice.showCorrectness,showRationale:choice.hasRationale&&(reviewMode||choice.showRationale),pos:i,onChange:newValues=>{if(editMode){return}onChoiceChange(i,newValues.checked);}};if(choice.isNoneOfTheAbove){Element=ChoiceNoneAbove$2;___default.default.extend(elementProps,{showContent:choice.revealNoneOfTheAbove});}const itemClassName=classNames__default.default(styles$y.item,styles$y.responsiveItem,choice.checked&&styles$y.selectedItem);let correctnessClass;if(reviewMode&&reviewModeRubric){correctnessClass=reviewModeRubric.choices[i].correct?ClassNames.CORRECT:ClassNames.INCORRECT;}const className=classNames__default.default(itemClassName,ClassNames.RADIO.OPTION,choice.checked&&ClassNames.RADIO.SELECTED,correctnessClass);let listElem=null;let clickHandler;if(editMode){clickHandler=e=>{let elem=e.target;while(elem&&elem!==listElem){if(elem.getAttribute("data-is-radio-icon")){onChoiceChange(i,!choice.checked);return}elem=elem.parentNode;}};}return jsxRuntimeExports.jsx("li",{ref:e=>listElem=e,className:className,onClick:clickHandler,onTouchStart:labelWrap?undefined:captureScratchpadTouchStart$2,children:jsxRuntimeExports.jsx(Element,{...elementProps,ref:ref})},i)})})})]});return jsxRuntimeExports.jsx("div",{className:styles$y.responsiveContainer,children:fieldset})};
|
|
1752
|
+
const MultipleChoiceComponent=({choices,countChoices,multipleSelect=false,numCorrect,onChoiceChange,reviewMode})=>{const{strings}=usePerseusI18n();const instructions=getInstructionsText$1({multipleSelect,countChoices,numCorrect,strings});const choiceListClasses=reviewMode?`${styles$z.choiceList} ${styles$z.reviewAnswers}`:styles$z.choiceList;return jsxRuntimeExports.jsxs("fieldset",{className:styles$z.container,"data-feature-flag":"feature flag is ON",children:[jsxRuntimeExports.jsx("legend",{className:styles$z.instructions,children:instructions}),jsxRuntimeExports.jsx(ScrollableView,{overflowX:"auto",children:jsxRuntimeExports.jsx("ul",{className:choiceListClasses,children:jsxRuntimeExports.jsx(ChoiceListItems,{choices:choices,i18nStrings:strings,onChoiceChange:onChoiceChange,reviewMode:reviewMode,multipleSelect:multipleSelect})})})]})};const ChoiceListItems=props=>{const{choices,i18nStrings,multipleSelect,onChoiceChange,reviewMode}=props;const items=choices.map((choice,i)=>{const updateChecked=isChecked=>{onChoiceChange(i,isChecked);};const choiceLetter=getChoiceLetter(i,i18nStrings);const showCorrectness=reviewMode===true?choice.correct?"correct":"wrong":undefined;const content=choice.isNoneOfTheAbove?i18nStrings.noneOfTheAbove:choice.content;const rationaleClasses=[styles$z.rationale].concat(showCorrectness==="correct"?[styles$z.isCorrect]:[]).join(" ");const rationale=reviewMode&&choice.hasRationale?jsxRuntimeExports.jsx("div",{className:rationaleClasses,children:choice.rationale}):undefined;return jsxRuntimeExports.jsx(Choice$2,{checked:choice.checked,indicatorContent:choiceLetter,isMultiSelect:multipleSelect,showCorrectness:showCorrectness,updateChecked:updateChecked,children:jsxRuntimeExports.jsxs("div",{className:styles$z.content,children:[content,rationale]})},choice.id)});return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:items})};
|
|
1757
1753
|
|
|
1758
1754
|
const getPromptJSON$p=renderProps=>{return {type:"passage-ref",options:{passageNumber:renderProps.passageNumber,referenceNumber:renderProps.referenceNumber,summaryText:renderProps.summaryText}}};
|
|
1759
1755
|
|
|
@@ -1763,9 +1759,9 @@ function addHighlight(existingHighlights,newHighlight){const newHighlights={};le
|
|
|
1763
1759
|
|
|
1764
1760
|
function getRelativePosition(child,parent){return {left:child.left-parent.left,top:child.top-parent.top}}function getRelativeRect({left,top,width,height},parent){return {...getRelativePosition({left,top},parent),width,height}}function getClientRectsForTextInRange(range){const mutableRects=[];addClientRectsForTextInNodeAndRange(range.commonAncestorContainer,range,mutableRects);return mutableRects}function addClientRectsForTextInNodeAndRange(node,range,mutableRects){const nodeContentsRange=new Range;nodeContentsRange.selectNodeContents(node);if(node.nodeType===Node.TEXT_NODE){const intersectedRange=intersectRanges(range,nodeContentsRange);if(intersectedRange){addClientRectsForText(node,intersectedRange,mutableRects);}}else if(node.nodeType===Node.ELEMENT_NODE){if(!rangesOverlap(range,nodeContentsRange)){return}for(const child of Array.from(node.childNodes)){addClientRectsForTextInNodeAndRange(child,range,mutableRects);}}}function addClientRectsForText(textNode,textRange,mutableRects){const parentElement=textNode.parentElement;const computedStyle=window.getComputedStyle(parentElement);let lineHeight=null;if(typeof computedStyle.lineHeight==="string"&&computedStyle.lineHeight.endsWith("px")){const parsedLineHeight=parseFloat(computedStyle.lineHeight);if(!isNaN(parsedLineHeight)){lineHeight=parsedLineHeight;}}const boundingRects=Array.from(textRange.getClientRects());for(const boundingRect of boundingRects){const rect={left:boundingRect.left,top:boundingRect.top,height:boundingRect.height,width:boundingRect.width};if(lineHeight!==null){const heightIncrease=lineHeight-rect.height;rect.top-=heightIncrease;rect.height=lineHeight;}mutableRects.push(rect);}}
|
|
1765
1761
|
|
|
1766
|
-
class HighlightRenderer extends React__namespace.PureComponent{UNSAFE_componentWillReceiveProps(nextProps){if(this.props.highlight!==nextProps.highlight||this.props.offsetParent!==nextProps.offsetParent){this.setState({cachedHighlightRects:this._computeRects(nextProps)});}}_computeRects(props){const{highlight,offsetParent}=props;const clientRects=getClientRectsForTextInRange(highlight.domRange);const{left,top}=offsetParent.getBoundingClientRect();const relativeRects=clientRects.map(rect=>getRelativeRect(rect,{left,top}));return relativeRects}_rectIsHovered(rect,mouseOffsetPosition){const positionWithinRect=getRelativePosition(mouseOffsetPosition,{left:rect.left,top:rect.top});return 0<=positionWithinRect.left&&positionWithinRect.left<rect.width&&0<=positionWithinRect.top&&positionWithinRect.top<rect.height}isHovered(mouseClientPosition){if(!mouseClientPosition){return false}const{offsetParent}=this.props;const{cachedHighlightRects}=this.state;const{left,top}=offsetParent.getBoundingClientRect();const mouseOffsetPosition=getRelativePosition(mouseClientPosition,{left,top});return cachedHighlightRects.some(rect=>this._rectIsHovered(rect,mouseOffsetPosition))}render(){const rects=this.state.cachedHighlightRects;return jsxRuntimeExports.jsx("div",{children:rects.map((rect,index)=>jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$
|
|
1762
|
+
class HighlightRenderer extends React__namespace.PureComponent{UNSAFE_componentWillReceiveProps(nextProps){if(this.props.highlight!==nextProps.highlight||this.props.offsetParent!==nextProps.offsetParent){this.setState({cachedHighlightRects:this._computeRects(nextProps)});}}_computeRects(props){const{highlight,offsetParent}=props;const clientRects=getClientRectsForTextInRange(highlight.domRange);const{left,top}=offsetParent.getBoundingClientRect();const relativeRects=clientRects.map(rect=>getRelativeRect(rect,{left,top}));return relativeRects}_rectIsHovered(rect,mouseOffsetPosition){const positionWithinRect=getRelativePosition(mouseOffsetPosition,{left:rect.left,top:rect.top});return 0<=positionWithinRect.left&&positionWithinRect.left<rect.width&&0<=positionWithinRect.top&&positionWithinRect.top<rect.height}isHovered(mouseClientPosition){if(!mouseClientPosition){return false}const{offsetParent}=this.props;const{cachedHighlightRects}=this.state;const{left,top}=offsetParent.getBoundingClientRect();const mouseOffsetPosition=getRelativePosition(mouseClientPosition,{left,top});return cachedHighlightRects.some(rect=>this._rectIsHovered(rect,mouseOffsetPosition))}render(){const rects=this.state.cachedHighlightRects;return jsxRuntimeExports.jsx("div",{children:rects.map((rect,index)=>jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$y.highlightRect),style:{position:"absolute",width:rect.width,height:rect.height,top:rect.top,left:rect.left,zIndex:this.props.zIndexes.belowContent}},index))})}constructor(...args){super(...args),this.state={cachedHighlightRects:this._computeRects(this.props),tooltipIsHovered:false};}}const styles$y=aphrodite.StyleSheet.create({highlightRect:{background:"#fffabe"}});
|
|
1767
1763
|
|
|
1768
|
-
class HighlightTooltip extends React__namespace.PureComponent{_getFocusRect(){const{focusNode,focusOffset,offsetParent}=this.props;const focusRange=document.createRange();focusRange.setStart(focusNode,focusOffset);focusRange.setEnd(focusNode,focusOffset);const focusRect=focusRange.getClientRects()[0];if(!focusRect){Log.log("[Highlighting] Known bug: Could not determine the focus "+'position, so did not show an "Add Highlight" tooltip. '+"https://app.asana.com/0/329800276300868/413878480039713 "+"(see also /r/asana-links)");return null}const{left,top}=offsetParent.getBoundingClientRect();const relativeFocusRect=getRelativeRect({left:focusRect.left,top:focusRect.top,width:focusRect.width,height:focusRect.height},{left,top});return relativeFocusRect}render(){const focusRect=this._getFocusRect();if(!focusRect){return null}const content=jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$
|
|
1764
|
+
class HighlightTooltip extends React__namespace.PureComponent{_getFocusRect(){const{focusNode,focusOffset,offsetParent}=this.props;const focusRange=document.createRange();focusRange.setStart(focusNode,focusOffset);focusRange.setEnd(focusNode,focusOffset);const focusRect=focusRange.getClientRects()[0];if(!focusRect){Log.log("[Highlighting] Known bug: Could not determine the focus "+'position, so did not show an "Add Highlight" tooltip. '+"https://app.asana.com/0/329800276300868/413878480039713 "+"(see also /r/asana-links)");return null}const{left,top}=offsetParent.getBoundingClientRect();const relativeFocusRect=getRelativeRect({left:focusRect.left,top:focusRect.top,width:focusRect.width,height:focusRect.height},{left,top});return relativeFocusRect}render(){const focusRect=this._getFocusRect();if(!focusRect){return null}const content=jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$x.tooltipLabel),onClick:this.props.onClick,children:this.props.label});const style={position:"absolute",left:focusRect.left,top:`calc(${Math.round(focusRect.top)}px + 0.95em)`,height:0};return jsxRuntimeExports.jsx("div",{style:style,onMouseEnter:this.props.onMouseEnter,onMouseLeave:this.props.onMouseLeave,children:jsxRuntimeExports.jsx(Tooltip__default.default,{content:content,opened:true,children:jsxRuntimeExports.jsx("div",{})})})}}const styles$x=aphrodite.StyleSheet.create({tooltipLabel:{userSelect:"none",fontFamily:`"Lato", sans-serif`,padding:`10px ${wonderBlocksTokens.spacing.medium_16}px`,cursor:"pointer"}});
|
|
1769
1765
|
|
|
1770
1766
|
class HighlightSetRenderer extends React__namespace.PureComponent{componentDidMount(){this._updateEditListeners(false,this.props.editable);}UNSAFE_componentWillReceiveProps(nextProps){this._updateEditListeners(this.props.editable,nextProps.editable);if(this.state.hoveredHighlightKey!=null&&!(this.state.hoveredHighlightKey in nextProps.highlights)){this.setState({hoveredHighlightKey:null});}if(this.state.hoveringTooltipFor!=null&&!(this.state.hoveringTooltipFor in nextProps.highlights)){this.setState({hoveringTooltipFor:null});}}componentWillUnmount(){this._updateEditListeners(this.props.editable,false);}_updateEditListeners(wasListening,willListen){if(!wasListening&&willListen){window.addEventListener("mousemove",this._handleMouseMove);}else if(wasListening&&!willListen){window.removeEventListener("mousemove",this._handleMouseMove);this.setState({hoveredHighlightKey:null,hoveringTooltipFor:null});}}_getHoveredHighlightKey(mouseClientPosition){const{hoveringTooltipFor}=this.state;if(typeof hoveringTooltipFor==="string"){return hoveringTooltipFor}const highlightKeys=Object.keys(this.props.highlights);return highlightKeys.find(key=>{const highlightRenderer=this._highlightRenderers[key];return highlightRenderer&&highlightRenderer.isHovered(mouseClientPosition)})}_renderTooltip(){const{hoveredHighlightKey}=this.state;if(hoveredHighlightKey==null){return null}const hoveredHighlight=this.props.highlights[hoveredHighlightKey];return jsxRuntimeExports.jsx(HighlightTooltip,{label:this.context.strings.removeHighlight,focusNode:hoveredHighlight.domRange.endContainer,focusOffset:hoveredHighlight.domRange.endOffset,offsetParent:this.props.offsetParent,onClick:()=>this.props.onRemoveHighlight(hoveredHighlightKey),onMouseEnter:()=>this.setState({hoveringTooltipFor:hoveredHighlightKey}),onMouseLeave:()=>this.setState({hoveringTooltipFor:null})})}render(){return jsxRuntimeExports.jsxs("div",{children:[Object.keys(this.props.highlights).map(key=>jsxRuntimeExports.jsx(HighlightRenderer,{ref:r=>{if(r){this._highlightRenderers[key]=r;}else {delete this._highlightRenderers[key];}},highlight:this.props.highlights[key],highlightKey:key,offsetParent:this.props.offsetParent,zIndexes:this.props.zIndexes},key)),this.props.editable&&this._renderTooltip()]})}constructor(...args){super(...args),this.state={hoveredHighlightKey:null,hoveringTooltipFor:null},this._highlightRenderers={},this._handleMouseMove=e=>{const mouseClientPosition={left:e.clientX,top:e.clientY};const hoveredHighlightKey=this._getHoveredHighlightKey(mouseClientPosition);this.setState({hoveredHighlightKey});};}}HighlightSetRenderer.contextType=PerseusI18nContext;
|
|
1771
1767
|
|
|
@@ -1775,41 +1771,47 @@ class HighlightingUI extends React__namespace.PureComponent{_handleAddHighlight(
|
|
|
1775
1771
|
|
|
1776
1772
|
class WordIndexer extends React__namespace.PureComponent{componentDidMount(){this._sendWordsUpdate();}componentDidUpdate(){this._sendWordsUpdate();}_sendWordsUpdate(){this.props.onWordsUpdate(this._getWordRanges());}_getWordRanges(){const container=this._container;if(!container){throw new perseusCore.PerseusError("invariant violation: `this._container` is not defined, but "+"this method is only called after mount/update",perseusCore.Errors.NotAllowed)}const treeWalker=container.ownerDocument.createTreeWalker(container,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT,()=>NodeFilter.FILTER_ACCEPT,false);const index=[];let trailingWordRange=null;while(treeWalker.nextNode()){const node=treeWalker.currentNode;if(node.nodeType===Node.ELEMENT_NODE){const element=node;if(getComputedStyle(element).display!=="inline"){trailingWordRange=null;}}else if(node.nodeType===Node.TEXT_NODE){const text=node.nodeValue;const wordPattern=/\S+/g;let wordMatch;let newTrailingWordRange=null;while((wordMatch=wordPattern.exec(text))!==null){const startOffset=wordMatch.index;const endOffset=wordMatch.index+wordMatch[0].length;let range;if(startOffset===0&&trailingWordRange){range=trailingWordRange;range.setEnd(node,endOffset);}else {range=node.ownerDocument.createRange();range.setStart(node,startOffset);range.setEnd(node,endOffset);index.push(range);}if(endOffset===text.length){newTrailingWordRange=range;}}trailingWordRange=newTrailingWordRange;}}return index}render(){return jsxRuntimeExports.jsx("div",{ref:container=>this._container=container,children:this.props.children})}}
|
|
1777
1773
|
|
|
1778
|
-
class HighlightableContent extends React__namespace.PureComponent{_buildHighlight(highlightRange){return buildHighlight(this._getDOMHighlights(),this.state.wordRanges,highlightRange)}_getDOMHighlights(){const{serializedHighlights}=this.props;const{wordRanges}=this.state;const domHighlights={};for(const key of Object.keys(serializedHighlights)){domHighlights[key]=deserializeHighlight(serializedHighlights[key],wordRanges);}return domHighlights}render(){const highlights=this._getDOMHighlights();const buildHighlight=r=>this._buildHighlight(r);return jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$
|
|
1774
|
+
class HighlightableContent extends React__namespace.PureComponent{_buildHighlight(highlightRange){return buildHighlight(this._getDOMHighlights(),this.state.wordRanges,highlightRange)}_getDOMHighlights(){const{serializedHighlights}=this.props;const{wordRanges}=this.state;const domHighlights={};for(const key of Object.keys(serializedHighlights)){domHighlights[key]=deserializeHighlight(serializedHighlights[key],wordRanges);}return domHighlights}render(){const highlights=this._getDOMHighlights();const buildHighlight=r=>this._buildHighlight(r);return jsxRuntimeExports.jsxs("div",{className:aphrodite.css(styles$w.container),ref:container=>this._container=container,children:[jsxRuntimeExports.jsx("div",{children:this.props.enabled&&this._container&&this._content&&jsxRuntimeExports.jsx(HighlightingUI,{buildHighlight:buildHighlight,contentNode:this._content,editable:this.props.editable,highlights:highlights,offsetParent:this._container,zIndexes:{belowContent:0},onAddHighlight:this._handleAddHighlight,onRemoveHighlight:this._handleRemoveHighlight})}),jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$w.content),ref:content=>this._content=content,children:jsxRuntimeExports.jsx(WordIndexer,{onWordsUpdate:this._handleWordsUpdate,children:this.props.children})})]})}constructor(...args){super(...args),this.state={wordRanges:[]},this._handleAddHighlight=highlight=>{const newDomHighlights=addHighlight(this._getDOMHighlights(),highlight);const newSerializedHighlights={};for(const key of Object.keys(newDomHighlights)){newSerializedHighlights[key]=serializeHighlight(newDomHighlights[key]);}this.props.onSerializedHighlightsUpdate(newSerializedHighlights);},this._handleRemoveHighlight=keyToRemove=>{const{serializedHighlights}=this.props;const newSerializedHighlights={...serializedHighlights};delete newSerializedHighlights[keyToRemove];this.props.onSerializedHighlightsUpdate(newSerializedHighlights);},this._handleWordsUpdate=wordRanges=>{this.setState({wordRanges});};}}const styles$w=aphrodite.StyleSheet.create({container:{position:"relative",zIndex:0},content:{position:"relative",zIndex:1}});
|
|
1779
1775
|
|
|
1780
1776
|
const getPromptJSON$o=renderProps=>{return {type:"passage",options:{passageTitle:renderProps.passageTitle,passageText:renderProps.passageText,footnotes:renderProps.footnotes}}};
|
|
1781
1777
|
|
|
1782
1778
|
function getInitialParseState(){return {currentRef:[],useRefs:true,lastRef:0,firstSentenceRef:null,firstQuestionRef:null,lastFootnote:{id:0,text:""}}}class RefStart extends React__namespace.Component{render(){return jsxRuntimeExports.jsx("span",{style:REF_STYLE,children:"_"})}constructor(...args){super(...args),this.getRefContent=()=>{return this.props.refContent};}}class RefEnd extends React__namespace.Component{render(){return jsxRuntimeExports.jsx("span",{style:REF_STYLE,children:"_"})}}const AltText=({id,number})=>{const{strings}=usePerseusI18n();return jsxRuntimeExports.jsx("span",{className:"perseus-sr-only",children:strings[id]({number})},"alt-text")};const rules={newline:SimpleMarkdown__default.default.defaultRules.newline,paragraph:SimpleMarkdown__default.default.defaultRules.paragraph,escape:SimpleMarkdown__default.default.defaultRules.escape,passageFootnote:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.1,match:SimpleMarkdown__default.default.inlineRegex(/^\^/),parse:(capture,parse,state)=>{const id=state.lastFootnote.id+1;const footnote={id:id,text:id===1?"*":""+id};if(state.lastFootnote.text==="*"){state.lastFootnote.text=""+state.lastFootnote.id;}state.lastFootnote=footnote;return footnote},react:(node,output,state)=>{return jsxRuntimeExports.jsx("sup",{children:node.text},state.key)}},refStart:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.2,match:function(source){const capture=/^\{\{/.exec(source);if(capture){let closeIndex=2;let refNestingLevel=0;while(closeIndex<source.length){const token=source.slice(closeIndex,closeIndex+2);if(token==="{{"){refNestingLevel++;closeIndex++;}else if(token==="}}"){if(refNestingLevel>0){refNestingLevel--;closeIndex++;}else {break}}closeIndex++;}capture[1]=source.slice(2,closeIndex);return capture}return null},parse:(capture,parse,state)=>{if(!state.useRefs){return {ref:null,refContent:null}}const ref=state.lastRef+1;state.lastRef=ref;state.currentRef.push(ref);const refContent=parse("(“"+capture[1]+"”)\n\n",___default.default.defaults({useRefs:false},getInitialParseState()));return {ref:ref,refContent:refContent}},react:(node,output,state)=>{const ref=node.ref;if(ref==null){return null}const refContent=output(node.refContent,{});return jsxRuntimeExports.jsx(RefStart,{ref:START_REF_PREFIX+ref,refContent:refContent},START_REF_PREFIX+ref)}},refEnd:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.3,match:SimpleMarkdown__default.default.inlineRegex(/^\}\}/),parse:(capture,parse,state)=>{if(!state.useRefs){return {ref:null}}const ref=state.currentRef.pop()||null;return {ref:ref}},react:(node,output,state)=>{if(node.ref!=null){return jsxRuntimeExports.jsx(RefEnd,{ref:END_REF_PREFIX+node.ref},END_REF_PREFIX+node.ref)}return null}},squareLabel:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.4,match:SimpleMarkdown__default.default.inlineRegex(/^\[\[(\w+)\]\]( *)/),parse:(capture,parse,state)=>{if(!state.firstQuestionRef){state.firstQuestionRef=capture[1];}return {content:capture[1],space:capture[2].length>0}},react:(node,output,state)=>{return [jsxRuntimeExports.jsx("span",{className:"perseus-passage-square-label",style:LABEL_OUTER_STYLE,"aria-hidden":"true",children:jsxRuntimeExports.jsx("span",{style:SQUARE_LABEL_STYLE,children:node.content})},"visual-square"),jsxRuntimeExports.jsx(AltText,{id:"questionMarker",number:node.content},"alt-text"),node.space?" ":null]}},circleLabel:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.5,match:SimpleMarkdown__default.default.inlineRegex(/^\(\((\w+)\)\)( *)/),parse:(capture,parse,state)=>{return {content:capture[1],space:capture[2].length>0}},react:(node,output,state)=>{return [jsxRuntimeExports.jsx("span",{className:"perseus-passage-circle-label",style:LABEL_OUTER_STYLE,"aria-hidden":true,children:jsxRuntimeExports.jsx("span",{style:CIRCLE_LABEL_STYLE,children:node.content})},"visual-circle"),jsxRuntimeExports.jsx(AltText,{id:"circleMarker",number:node.content},"alt-text"),node.space?" ":null]}},squareBracketRef:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.6,match:SimpleMarkdown__default.default.inlineRegex(/^\[(\d+)\]( *)/),parse:(capture,parse,state)=>{if(!state.firstSentenceRef){state.firstSentenceRef=capture[1];}return {content:capture[1],space:capture[2].length>0}},react:(node,output,state)=>{return [jsxRuntimeExports.jsxs("span",{className:"perseus-passage-bracket-label","aria-hidden":"true",children:["[",node.content,"]"]},"visual-brackets"),jsxRuntimeExports.jsx(AltText,{id:"sentenceMarker",number:node.content},"alt-text"),node.space?" ":null]}},highlight:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.7,match:SimpleMarkdown__default.default.inlineRegex(/^{highlighting.start}(.+?){highlighting.end}/),parse:(capture,parse,state)=>{return {content:capture[1]}},react:(node,output,state)=>{return [jsxRuntimeExports.jsx("span",{className:"perseus-highlight",children:node.content},0)]}},reviewHighlight:{order:SimpleMarkdown__default.default.defaultRules.escape.order+.7,match:SimpleMarkdown__default.default.inlineRegex(/^{review-highlighting.start}(.+?){review-highlighting.end}/),parse:(capture,parse,state)=>{return {content:capture[1]}},react:(node,output,state)=>{return [jsxRuntimeExports.jsx("span",{className:"perseus-review-highlight",children:node.content},0)]}},strong:SimpleMarkdown__default.default.defaultRules.strong,u:SimpleMarkdown__default.default.defaultRules.u,em:SimpleMarkdown__default.default.defaultRules.em,del:SimpleMarkdown__default.default.defaultRules.del,text:{...SimpleMarkdown__default.default.defaultRules.text,react(node,output,state){return jsxRuntimeExports.jsx("span",{children:node.content},state.key)}}};const START_REF_PREFIX="start-ref-";const END_REF_PREFIX="end-ref-";const REF_STYLE={display:"inline-block",width:0,visibility:"hidden"};const LABEL_OUTER_STYLE={display:"inline",whiteSpace:"nowrap"};const SQUARE_LABEL_STYLE={display:"inline-block",color:"rgb(255, 255, 255)",backgroundColor:"rgb(90, 90, 90)",paddingLeft:10,paddingRight:10,userSelect:"none",WebkitUserSelect:"none"};const CIRCLE_LABEL_STYLE={display:"inline-block",color:"rgb(255, 255, 255)",backgroundColor:"rgb(90, 90, 90)",userSelect:"none",WebkitUserSelect:"none",width:22,height:22,borderRadius:"50%",textAlign:"center"};const builtParser=SimpleMarkdown__default.default.parserFor(rules);const parse$2=(source,state)=>{state=state||{};const paragraphedSource=source+"\n\n";return builtParser(paragraphedSource,___default.default.extend(state,getInitialParseState()))};const output=SimpleMarkdown__default.default.reactFor(SimpleMarkdown__default.default.ruleOutput(rules,"react"));var PassageMarkdown = {parse: parse$2,output,START_REF_PREFIX,END_REF_PREFIX,getInitialParseState};
|
|
1783
1779
|
|
|
1784
|
-
class LineHeightMeasurer extends React__namespace.Component{measureLineHeight(){if(!this._line){return 0}return this._line.clientHeight}render(){return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$
|
|
1780
|
+
class LineHeightMeasurer extends React__namespace.Component{measureLineHeight(){if(!this._line){return 0}return this._line.clientHeight}render(){return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$v.measurer),"aria-hidden":"true",children:jsxRuntimeExports.jsx("div",{ref:ref=>this._line=ref,className:"paragraph",children:"Line Height Measurement"})})}}const styles$v=aphrodite.StyleSheet.create({measurer:{position:"absolute",top:0,left:0,visibility:"hidden",zIndex:-1}});class Passage extends React__namespace.Component{componentDidMount(){this._updateState();this._onResize=___default.default.throttle(()=>{if(this.shouldRenderJipt()){return}this._lineHeightMeasurerRef?.measureLineHeight();this._updateState();},500);window.addEventListener("resize",this._onResize);this._stylesAppiedTimer=window.setTimeout(()=>{this.setState({stylesAreApplied:true});},0);}shouldComponentUpdate(nextProps,nextState){return !___default.default.isEqual(this.props,nextProps)||!___default.default.isEqual(this.state,nextState)}componentDidUpdate(){this._updateState();}componentWillUnmount(){window.removeEventListener("resize",this._onResize);clearTimeout(this._stylesAppiedTimer);}_updateState(){if(this.shouldRenderJipt()){return}this.setState({nLines:this._measureLines(),startLineNumbersAfter:this._getInitialLineNumber()});}_measureLines(){const renderer=ReactDOM__namespace.findDOMNode(this._contentRef);const contentsHeight=$__default.default(renderer).height();const lineHeight=this._getLineHeight();const nLines=Math.round(contentsHeight/lineHeight);return nLines}_getInitialLineNumber(){let isPassageBeforeThisPassage=true;const passagesBeforeUs=this.props.findWidgets((id,widgetInfo)=>{if(widgetInfo.type!=="passage"){return false}if(id===this.props.widgetId){isPassageBeforeThisPassage=false;}return isPassageBeforeThisPassage}).filter(isPassageWidget);return passagesBeforeUs.map(passageWidget=>{return passageWidget.getLineCount()}).reduce((a,b)=>a+b,0)}_getLineHeight(){return this._lineHeightMeasurerRef?.measureLineHeight()||0}getLineCount(){if(this.state.nLines!=null){return this.state.nLines}return this._measureLines()}_getStartRefLineNumber(referenceNumber){const refRef=PassageMarkdown.START_REF_PREFIX+referenceNumber;const ref=this.refs[refRef];if(!ref){return null}const $ref=$__default.default(ReactDOM__namespace.findDOMNode(ref));let $refText=$ref.next();if($refText.length===0){$refText=$ref;}const vPos=$refText.offset().top;return this.state.startLineNumbersAfter+1+this._convertPosToLineNumber(vPos)}_getEndRefLineNumber(referenceNumber){const refRef=PassageMarkdown.END_REF_PREFIX+referenceNumber;const ref=this.refs[refRef];if(!ref){return null}const $ref=$__default.default(ReactDOM__namespace.findDOMNode(ref));let $refText=$ref.prev();if($refText.length===0){$refText=$ref;}const height=$refText.height();const vPos=$refText.offset().top;let line=this._convertPosToLineNumber(vPos+height);if(height===0){line+=1;}return this.state.startLineNumbersAfter+line}_convertPosToLineNumber(absoluteVPos){const content=ReactDOM__namespace.findDOMNode(this._contentRef);const relativeVPos=absoluteVPos-$__default.default(content).offset().top;const lineHeight=this._getLineHeight();const line=Math.round(relativeVPos/lineHeight);return line}_getRefContent(referenceNumber){const refRef=PassageMarkdown.START_REF_PREFIX+referenceNumber;const ref=this.refs[refRef];if(!ref){return null}return ref.getRefContent()}getReference(referenceNumber){const refStartLine=this._getStartRefLineNumber(referenceNumber);const refEndLine=this._getEndRefLineNumber(referenceNumber);if(refStartLine==null||refEndLine==null){return null}const refContent=this._getRefContent(referenceNumber);return {startLine:refStartLine,endLine:refEndLine,content:refContent}}getPromptJSON(){return getPromptJSON$o(this.props)}_renderInstructions(parseState){const firstQuestionNumber=parseState.firstQuestionRef;const firstSentenceRef=parseState.firstSentenceRef;const{strings}=this.context;let instructions="";if(firstQuestionNumber){instructions+=strings.symbolPassage({questionSymbol:"[["+firstQuestionNumber+"]]",questionNumber:firstQuestionNumber});}if(firstSentenceRef){instructions+=strings.symbolQuestion({sentenceSymbol:"["+firstSentenceRef+"]"});}const parsedInstructions=PassageMarkdown.parse(instructions);return jsxRuntimeExports.jsx("div",{className:"perseus-widget-passage-instructions",children:PassageMarkdown.output(parsedInstructions)})}shouldRenderJipt(){const{JIPT}=getDependencies();return JIPT.useJIPT&&this.props.passageText.indexOf("crwdns")!==-1}_renderContent(parsed){const enabled=this.state.stylesAreApplied;const editable=!this.props.reviewMode;return jsxRuntimeExports.jsx(HighlightableContent,{editable:editable,enabled:enabled,onSerializedHighlightsUpdate:this._handleSerializedHighlightsUpdate,serializedHighlights:this.props.highlights,children:jsxRuntimeExports.jsxs("div",{ref:ref=>this._contentRef=ref,children:[jsxRuntimeExports.jsx(LineHeightMeasurer,{ref:ref=>this._lineHeightMeasurerRef=ref}),PassageMarkdown.output(parsed)]})})}_hasFootnotes(){const rawContent=this.props.footnotes;const isEmpty=/^\s*$/.test(rawContent);return !isEmpty}_renderFootnotes(){const rawContent=this.props.footnotes;const parsed=PassageMarkdown.parse(rawContent);return PassageMarkdown.output(parsed)}render(){const{strings}=this.context;let lineNumbers;const nLines=this.state.nLines;if(this.props.showLineNumbers&&nLines){lineNumbers=___default.default.range(1,nLines+1).map(lineN=>{const lineAt=lineN+this.state.startLineNumbersAfter;if(lineAt===4){const translatedLine=strings.lineLabel;return jsxRuntimeExports.jsx("span",{className:"line-marker",children:translatedLine},"line-marker")}return jsxRuntimeExports.jsx("span",{children:lineAt},lineN)});}const parseState=PassageMarkdown.getInitialParseState();const re=/("{1})([^"]*)("{1})/g;const doubleQuoteParsedContent=this.props.passageText.replace(re,"“$2”");const parsedContent=PassageMarkdown.parse(doubleQuoteParsedContent,parseState);const hasTitle=/\S/.test(this.props.passageTitle);return jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-passage-container",children:[this._renderInstructions(parseState),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-passage",children:[hasTitle&&jsxRuntimeExports.jsx("h3",{className:"passage-title",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.passageTitle,linterContext:this.props.linterContext,strings:strings})}),lineNumbers&&jsxRuntimeExports.jsx("div",{className:"line-numbers","aria-hidden":true,children:lineNumbers}),!hasTitle&&jsxRuntimeExports.jsx("h3",{className:"perseus-sr-only",children:strings.beginningPassage}),jsxRuntimeExports.jsx("div",{className:"passage-text",children:this.shouldRenderJipt()?jsxRuntimeExports.jsx(Renderer,{content:this.props.passageText,strings:strings}):this._renderContent(parsedContent)}),this._hasFootnotes()&&[jsxRuntimeExports.jsx("h4",{className:"perseus-sr-only",children:strings.beginningFootnotes},"footnote-start"),jsxRuntimeExports.jsx("div",{className:"footnotes",children:this._renderFootnotes()},"footnotes")],jsxRuntimeExports.jsx("div",{className:"perseus-sr-only",children:strings.endPassage})]})]})})}constructor(...args){super(...args),this.isWidget=true,this.state={nLines:null,startLineNumbersAfter:0,stylesAreApplied:false},this._handleSerializedHighlightsUpdate=serializedHighlights=>{this.props.onChange({highlights:serializedHighlights});};}}Passage.contextType=PerseusI18nContext;Passage.defaultProps={passageTitle:"",passageText:"",footnotes:"",showLineNumbers:true,highlights:{},linterContext:PerseusLinter.linterContextDefault};var Passage$1 = {name:"passage",displayName:"Passage (SAT only)",hidden:true,widget:Passage,isLintable:true};
|
|
1785
1781
|
|
|
1786
1782
|
function isPassageWidget(widget){return widget instanceof Passage}
|
|
1787
1783
|
|
|
1788
|
-
const EN_DASH$1="–";class PassageRef extends React__namespace.Component{componentDidMount(){this._isMounted=true;this._deferredUpdateRange();this._throttledUpdateRange=___default.default.throttle(this._deferredUpdateRange,500);window.addEventListener("resize",this._throttledUpdateRange);}shouldComponentUpdate(nextProps,nextState){return !___default.default.isEqual(this.props,nextProps)||!___default.default.isEqual(this.state,nextState)}componentDidUpdate(){this._deferredUpdateRange();}componentWillUnmount(){window.removeEventListener("resize",this._throttledUpdateRange);this._isMounted=false;}getPromptJSON(){return getPromptJSON$p(this.props)}render(){const{strings}=this.context;const lineRange=this.state.lineRange;let lineRangeOutput;if(!lineRange){lineRangeOutput=strings.lineRange({lineRange:`?${EN_DASH$1}?`});}else if(lineRange[0]===lineRange[1]){lineRangeOutput=strings.lineNumber({lineNumber:String(lineRange[0])});}else {lineRangeOutput=strings.lineRange({lineRange:lineRange[0]+EN_DASH$1+lineRange[1]});}let summaryOutput;if(this.props.summaryText){const summaryTree=PerseusMarkdown.parseInline(this.props.summaryText);summaryOutput=jsxRuntimeExports.jsxs("span",{"aria-hidden":true,children:[" ","(“",PerseusMarkdown.basicOutput(summaryTree),"”)"]});}else {summaryOutput=null;}return jsxRuntimeExports.jsxs("span",{children:[lineRangeOutput,summaryOutput,lineRange&&jsxRuntimeExports.jsx("div",{className:"perseus-sr-only",children:this.state.content})]})}constructor(...args){super(...args),this.displayName="PassageRef",this.isWidget=true,this.state={lineRange:null,content:null},this._deferredUpdateRange=()=>{___default.default.defer(this._updateRange);},this._updateRange=()=>{const passage=this.props.findWidgets("passage "+this.props.passageNumber).filter(isPassageWidget)[0];const refInfo=passage?.getReference(this.props.referenceNumber);if(this._isMounted){if(refInfo){this.setState({lineRange:[refInfo.startLine,refInfo.endLine],content:refInfo.content});}else {this.setState({lineRange:null,content:null});}}};}}PassageRef.contextType=PerseusI18nContext;PassageRef.defaultProps={passageNumber:1,referenceNumber:1,summaryText:""};var PassageRef$1 = {name:"passage-ref",displayName:"PassageRef (SAT only)",hidden:true,widget:PassageRef,
|
|
1784
|
+
const EN_DASH$1="–";class PassageRef extends React__namespace.Component{componentDidMount(){this._isMounted=true;this._deferredUpdateRange();this._throttledUpdateRange=___default.default.throttle(this._deferredUpdateRange,500);window.addEventListener("resize",this._throttledUpdateRange);}shouldComponentUpdate(nextProps,nextState){return !___default.default.isEqual(this.props,nextProps)||!___default.default.isEqual(this.state,nextState)}componentDidUpdate(){this._deferredUpdateRange();}componentWillUnmount(){window.removeEventListener("resize",this._throttledUpdateRange);this._isMounted=false;}getPromptJSON(){return getPromptJSON$p(this.props)}render(){const{strings}=this.context;const lineRange=this.state.lineRange;let lineRangeOutput;if(!lineRange){lineRangeOutput=strings.lineRange({lineRange:`?${EN_DASH$1}?`});}else if(lineRange[0]===lineRange[1]){lineRangeOutput=strings.lineNumber({lineNumber:String(lineRange[0])});}else {lineRangeOutput=strings.lineRange({lineRange:lineRange[0]+EN_DASH$1+lineRange[1]});}let summaryOutput;if(this.props.summaryText){const summaryTree=PerseusMarkdown.parseInline(this.props.summaryText);summaryOutput=jsxRuntimeExports.jsxs("span",{"aria-hidden":true,children:[" ","(“",PerseusMarkdown.basicOutput(summaryTree),"”)"]});}else {summaryOutput=null;}return jsxRuntimeExports.jsxs("span",{children:[lineRangeOutput,summaryOutput,lineRange&&jsxRuntimeExports.jsx("div",{className:"perseus-sr-only",children:this.state.content})]})}constructor(...args){super(...args),this.displayName="PassageRef",this.isWidget=true,this.state={lineRange:null,content:null},this._deferredUpdateRange=()=>{___default.default.defer(this._updateRange);},this._updateRange=()=>{const passage=this.props.findWidgets("passage "+this.props.passageNumber).filter(isPassageWidget)[0];const refInfo=passage?.getReference(this.props.referenceNumber);if(this._isMounted){if(refInfo){this.setState({lineRange:[refInfo.startLine,refInfo.endLine],content:refInfo.content});}else {this.setState({lineRange:null,content:null});}}};}}PassageRef.contextType=PerseusI18nContext;PassageRef.defaultProps={passageNumber:1,referenceNumber:1,summaryText:""};var PassageRef$1 = {name:"passage-ref",displayName:"PassageRef (SAT only)",hidden:true,widget:PassageRef,version:perseusCore.passageRefLogic.version};
|
|
1789
1785
|
|
|
1790
1786
|
const getChoiceStates=({choices,isStatic,showSolutions,choiceStates,values})=>{const defaultState={selected:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false};if(isStatic||showSolutions==="all"){return choices.map(choice=>({...defaultState,selected:!!choice.correct,readOnly:true,rationaleShown:true,correctnessShown:true}))}if(choiceStates){return choiceStates}if(values){return values.map(val=>({...defaultState,selected:val}))}return choices.map(()=>({...defaultState}))};const parseNestedWidgets=content=>{let nextPassageRefId=1;const extractedWidgets={};const parsedContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(_,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;extractedWidgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return {parsedContent,extractedWidgets}};
|
|
1791
1787
|
|
|
1792
|
-
class MultipleChoiceWidget extends React__namespace.Component{getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const choicesProps=this.prepareChoicesProps();const{apiOptions,
|
|
1788
|
+
class MultipleChoiceWidget extends React__namespace.Component{getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const choicesProps=this.prepareChoicesProps();const{apiOptions,reviewMode,multipleSelect,countChoices,numCorrect}=this.props;const onChoiceChange=apiOptions.readOnly||reviewMode?()=>{}:this.handleChoiceChange;return jsxRuntimeExports.jsx(MultipleChoiceComponent,{reviewMode:reviewMode,multipleSelect:multipleSelect,countChoices:countChoices,numCorrect:numCorrect,choices:choicesProps,onChoiceChange:onChoiceChange})}constructor(...args){super(...args),this.renderContent=(content="")=>{const{parsedContent,extractedWidgets}=parseNestedWidgets(content);const{strings=mockStrings,findWidgets}=this.props;const linterContext={contentType:"radio",highlightLint:false,paths:[],stack:[]};return jsxRuntimeExports.jsx(Renderer,{content:parsedContent,widgets:extractedWidgets,findExternalWidgets:findWidgets,alwaysUpdate:true,linterContext:linterContext,strings:strings},"choiceContentRenderer")},this.handleChoiceChange=(choiceIndex,newCheckedState)=>{const{choices,choiceStates,multipleSelect=false,onChange,trackInteraction}=this.props;let newCheckedList;if(newCheckedState&&!multipleSelect){newCheckedList=choices.map(()=>false);}else {newCheckedList=choiceStates?choiceStates.map(state=>state.selected):choices.map(()=>false);}newCheckedList[choiceIndex]=newCheckedState;const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{choiceState.selected=newCheckedList[i];});onChange({choiceStates:newChoiceStates});trackInteraction();},this.buildChoiceProps=choiceStates=>{const{choices,reviewModeRubric,questionCompleted,strings=mockStrings}=this.props;return choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,previouslyAnswered}=choiceStates[i];const reviewChoice=reviewModeRubric?.choices[i];return {id:choice.id,content:this.renderContent(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:this.renderContent(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(questionCompleted&&selected),previouslyAnswered}})},this.prepareChoicesProps=()=>{const{choices,showSolutions,choiceStates,values}=this.props;const processedChoiceStates=getChoiceStates({choices,isStatic:this.props.static,showSolutions,choiceStates,values});const choicesProps=this.buildChoiceProps(processedChoiceStates);return choicesProps};}}MultipleChoiceWidget.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:PerseusLinter.linterContextDefault,showSolutions:"none"};const Radio$3=MultipleChoiceWidget;
|
|
1789
|
+
|
|
1790
|
+
const{pureXsMax,pureSmMax,pureMdMin,pureMdMax,pureLgMin,pureLgMax,pureXlMin}=constants;var mediaQueries = {md:`@media screen and (min-width: ${pureMdMin}) and `+`(max-width: ${pureMdMax})`,xl:`@media screen and (min-width: ${pureXlMin})`,xsOrSmaller:`@media screen and (max-width: ${pureXsMax})`,smOrSmaller:`@media screen and (max-width: ${pureSmMax})`,mdOrSmaller:`@media screen and (max-width: ${pureMdMax})`,lgOrSmaller:`@media screen and (max-width: ${pureLgMax})`,lgOrLarger:`@media screen and (min-width: ${pureLgMin})`};
|
|
1791
|
+
|
|
1792
|
+
if(typeof HTMLElement!=="undefined"&&!HTMLElement.prototype.scrollTo){HTMLElement.prototype.scrollTo=function(left,top){this.scrollLeft=left;this.scrollTop=top;};}const applyUniversalScrollOffset=(elementOrWindow,amount)=>{if(typeof elementOrWindow.scrollTo==="function"){elementOrWindow.scrollTo(0,amount);}else if("scrollTop"in elementOrWindow){elementOrWindow.scrollTop=amount;}};const scrollElementToOffset=(elementOrWindow,offset,duration=0,callback)=>{const startPosition=elementOrWindow===window?window.pageYOffset:elementOrWindow.scrollTop;const endPosition=offset;const scrollDistance=endPosition-startPosition;const tickLength=17;const numberOfSteps=duration/tickLength;let step=0;const scrollInterval=setInterval(function(){if(step<numberOfSteps){const x=step/numberOfSteps;const y=(-Math.cos(Math.PI*x)+1)/2;const newPosition=startPosition+scrollDistance*y;applyUniversalScrollOffset(elementOrWindow,newPosition);step+=1;}else {applyUniversalScrollOffset(elementOrWindow,endPosition);clearInterval(scrollInterval);}},tickLength);};const getScrollContainer=element=>{if(element===document.body){return window}if(element==null){return window}if(element.scrollHeight>element.clientHeight){return element}return getScrollContainer(element.parentElement)};const SCROLL_ANIMATION_DURATION=750;const scrollElementIntoView=(element,callback)=>{setTimeout(()=>{const scrollContainer=getScrollContainer(element);const childBounds=element.getBoundingClientRect();const containerBounds=scrollContainer===window?{top:0,bottom:window.innerHeight}:scrollContainer.getBoundingClientRect();let offset=0;const currentScrollTop=scrollContainer===window?window.scrollY:scrollContainer.scrollTop;if(childBounds.bottom>containerBounds.bottom){let distanceToScroll=childBounds.bottom-containerBounds.bottom;if(childBounds.top+distanceToScroll<containerBounds.top){distanceToScroll=childBounds.top-containerBounds.top;}offset=currentScrollTop+distanceToScroll;}else if(childBounds.top<containerBounds.top){const distanceToScroll=childBounds.top-containerBounds.top;offset=currentScrollTop+distanceToScroll;}scrollElementToOffset(scrollContainer,offset,SCROLL_ANIMATION_DURATION);},0);};
|
|
1793
1793
|
|
|
1794
1794
|
function getA11yText(letter,checked,correct,showCorrectness,strings){if(showCorrectness&&correct){if(checked){return strings.choiceCheckedCorrect({letter})}return strings.choiceCorrect({letter})}if(showCorrectness&&!correct){if(checked){return strings.choiceCheckedIncorrect({letter})}return strings.choiceIncorrect({letter})}if(checked){return strings.choiceChecked({letter})}return strings.choice({letter})}
|
|
1795
1795
|
|
|
1796
|
+
const FocusRing=function({visible=true,color=kaGreen,multipleSelect=false,children}){const borderColor=visible?color:"transparent";const borderRadius=multipleSelect?5:"50%";const style={borderColor,borderRadius};return jsxRuntimeExports.jsx("span",{"data-testid":"focus-ring",className:aphrodite.css(styles$u.ring),style:style,children:children})};const styles$u=aphrodite.StyleSheet.create({ring:{margin:"auto",display:"inline-block",borderWidth:2,padding:2,borderStyle:"solid"}});
|
|
1797
|
+
|
|
1796
1798
|
const CHOICE_ICON_SIZE=24;const styles$t=aphrodite.StyleSheet.create({iconWrapper:{display:"inline-block",position:"relative"}});
|
|
1797
1799
|
|
|
1798
|
-
function ChoiceInner(props){const{pos,showCorrectness,correct}=props;const{strings}=usePerseusI18n();const letter=getChoiceLetter
|
|
1800
|
+
function ChoiceInner(props){const{pos,showCorrectness,correct}=props;const{strings}=usePerseusI18n();const letter=getChoiceLetter(pos,strings);if(!showCorrectness){return jsxRuntimeExports.jsx("span",{children:letter})}if(correct){return jsxRuntimeExports.jsx(InlineIcon,{...iconCheck,style:{position:"relative",top:-1}})}return jsxRuntimeExports.jsx(InlineIcon,{...iconMinus})}const ChoiceIcon=function(props){const{checked,showCorrectness,correct,focused,hovered,multipleSelect,pos,previouslyAnswered,pressed}=props;const choiceIsChecked=checked||showCorrectness&&!correct&&previouslyAnswered;const choiceStyling=[styles$s.choiceBase,multipleSelect?styles$s.multiSelectShape:styles$s.singleSelectShape,showCorrectness?styles$s.choiceHasIcon:styles$s.choiceHasLetter,choiceIsChecked?styles$s.choiceIsChecked:styles$s.choiceIsUnchecked];if(showCorrectness&&correct&&checked){choiceStyling.push(styles$s.choiceCorrect);}else if(showCorrectness&&!correct&&(checked||previouslyAnswered)){choiceStyling.push(styles$s.choiceIncorrect);}else if(checked){choiceStyling.push(styles$s.choiceNeutral);}else if(pressed){choiceStyling.push(styles$s.activeNeutral);}else {choiceStyling.push(styles$s.uncheckedColors);}return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$t.iconWrapper),children:jsxRuntimeExports.jsx(FocusRing,{color:wonderBlocksTokens.color.blue,visible:focused||hovered,multipleSelect:multipleSelect,children:jsxRuntimeExports.jsx("div",{"data-testid":"choice-icon__library-choice-icon",className:aphrodite.css(...choiceStyling),"data-is-radio-icon":true,children:jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$s.innerWrapper),children:jsxRuntimeExports.jsx(ChoiceInner,{pos:pos,showCorrectness:showCorrectness,correct:correct})})})})})};const styles$s=aphrodite.StyleSheet.create({innerWrapper:{width:CHOICE_ICON_SIZE,height:CHOICE_ICON_SIZE,display:"flex",alignItems:"center",justifyContent:"center"},choiceBase:{width:CHOICE_ICON_SIZE,height:CHOICE_ICON_SIZE,boxSizing:"border-box",borderStyle:"solid",borderWidth:2,fontFamily:baseFontFamily,fontWeight:"bold",display:"flex",alignItems:"center",justifyContent:"center"},choiceHasLetter:{fontSize:12},choiceHasIcon:{fontSize:CHOICE_ICON_SIZE},choiceIsChecked:{color:wonderBlocksTokens.color.white},choiceIsUnchecked:{color:wonderBlocksTokens.color.offBlack64},choiceCorrect:{backgroundColor:wonderBlocksTokens.color.green,borderColor:wonderBlocksTokens.color.green},choiceIncorrect:{backgroundColor:wonderBlocksTokens.color.red,borderColor:wonderBlocksTokens.color.red},choiceNeutral:{backgroundColor:wonderBlocksTokens.color.blue,borderColor:wonderBlocksTokens.color.blue},activeNeutral:{color:wonderBlocksTokens.color.blue,borderColor:wonderBlocksTokens.color.blue,backgroundColor:"transparent"},multiSelectShape:{borderRadius:3},singleSelectShape:{borderRadius:CHOICE_ICON_SIZE},uncheckedColors:{borderColor:wonderBlocksTokens.color.offBlack64}});
|
|
1799
1801
|
|
|
1800
1802
|
function renderText(checked,correct,strings){if(correct){if(checked){return strings.correctSelected}return strings.correct}if(checked){return strings.incorrectSelected}return strings.incorrect}const OptionStatus=function(props){const{checked,correct,previouslyAnswered,reviewMode}=props;const{strings}=usePerseusI18n();if(!reviewMode&&!previouslyAnswered){return null}let textStyle;if(correct){textStyle=styles$r.correct;}else {if(checked||previouslyAnswered){textStyle=styles$r.incorrectAnswered;}else {textStyle=styles$r.incorrect;}}return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$r.text,textStyle),children:renderText(checked,correct,strings)})};const styles$r=aphrodite.StyleSheet.create({text:{alignItems:"center",display:"flex",fontSize:12,height:32,textTransform:"uppercase"},correct:{color:wonderBlocksTokens.color.green},incorrectAnswered:{color:wonderBlocksTokens.color.red},incorrect:{color:wonderBlocksTokens.color.offBlack64}});
|
|
1801
1803
|
|
|
1802
|
-
const intermediateCheckboxPadding=`16px 16px`;const intermediateCheckboxPaddingPhone=`12px 16px`;const Choice=function(props){const{disabled=false,checked=false,content,showCorrectness,multipleSelect,onChange=newValues=>{},reviewMode,correct=false,apiOptions=ApiOptions.defaults,previouslyAnswered=false,pos=0,showRationale=false,rationale,forwardedRef}=props;const[isInputFocused,setIsInputFocused]=React.useState(false);const{strings}=usePerseusI18n();React.useEffect(()=>{if(isInputFocused&&disabled){setIsInputFocused(false);}},[disabled,isInputFocused,setIsInputFocused]);function sendChange(newValues){const updatedChecked=newValues.checked??checked;onChange({checked:updatedChecked});}const descriptionClassName=classNames__default.default("description",aphrodite.css(styles$q.description));const rationaleClassName=classNames__default.default("perseus-radio-rationale-content",aphrodite.css(styles$q.rationale));const showDimmed=!reviewMode&&apiOptions.readOnly;const letter=getChoiceLetter
|
|
1804
|
+
const intermediateCheckboxPadding=`16px 16px`;const intermediateCheckboxPaddingPhone=`12px 16px`;const Choice=function(props){const{disabled=false,checked=false,content,showCorrectness,multipleSelect,onChange=newValues=>{},reviewMode,correct=false,apiOptions=ApiOptions.defaults,previouslyAnswered=false,pos=0,showRationale=false,rationale,forwardedRef}=props;const[isInputFocused,setIsInputFocused]=React.useState(false);const{strings}=usePerseusI18n();React.useEffect(()=>{if(isInputFocused&&disabled){setIsInputFocused(false);}},[disabled,isInputFocused,setIsInputFocused]);function sendChange(newValues){const updatedChecked=newValues.checked??checked;onChange({checked:updatedChecked});}const descriptionClassName=classNames__default.default("description",aphrodite.css(styles$q.description));const rationaleClassName=classNames__default.default("perseus-radio-rationale-content",aphrodite.css(styles$q.rationale));const showDimmed=!reviewMode&&apiOptions.readOnly;const letter=getChoiceLetter(pos,strings);const a11yText=getA11yText(letter,checked,correct,showCorrectness,strings);return jsxRuntimeExports.jsxs("div",{style:{dispay:"flex",flexDirection:"column",color:wonderBlocksTokens.color.offBlack},className:descriptionClassName,children:[jsxRuntimeExports.jsxs("div",{style:{display:"flex",flexDirection:"row",opacity:showDimmed?.5:1,overflowX:"auto",overflowY:"hidden"},children:[jsxRuntimeExports.jsx("div",{className:"perseus-sr-only",children:jsxRuntimeExports.jsxs("label",{children:[a11yText," ",content,jsxRuntimeExports.jsx("input",{type:multipleSelect?"checkbox":"radio",checked:checked,onClick:()=>{sendChange({checked:!checked});},onChange:()=>{},disabled:disabled||apiOptions.readOnly,tabIndex:-1,className:ClassNames.RADIO.OPTION_CONTENT})]})}),jsxRuntimeExports.jsx(Clickable__default.default,{onClick:()=>{sendChange({checked:!checked});},disabled:disabled||apiOptions.readOnly,style:{flex:1,color:wonderBlocksTokens.color.offBlack,userSelect:"text"},ref:forwardedRef,"aria-hidden":"true",children:({hovered,focused,pressed})=>jsxRuntimeExports.jsxs("div",{style:{display:"flex",flexDirection:"row",justifyContent:"center",alignContent:"center",paddingTop:wonderBlocksTokens.spacing.xSmall_8,paddingBottom:wonderBlocksTokens.spacing.xSmall_8,paddingLeft:wonderBlocksTokens.spacing.xSmall_8},children:[jsxRuntimeExports.jsx(ChoiceIcon,{pos:pos,correct:correct,pressed:pressed,focused:focused,checked:checked,hovered:hovered,showCorrectness:showCorrectness,multipleSelect:multipleSelect,reviewMode:reviewMode,previouslyAnswered:previouslyAnswered}),jsxRuntimeExports.jsxs("span",{style:{paddingLeft:wonderBlocksTokens.spacing.small_12,textAlign:"left",flex:1,paddingTop:4},children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(OptionStatus,{checked:checked,correct:correct,previouslyAnswered:previouslyAnswered,reviewMode:reviewMode})}),jsxRuntimeExports.jsx("div",{children:content})]})]})})]}),showRationale&&jsxRuntimeExports.jsx("div",{className:rationaleClassName,"data-testid":`perseus-radio-rationale-content-${pos}`,children:rationale})]})};const styles$q=aphrodite.StyleSheet.create({description:{display:"inline-block",width:"100%"},rationale:{display:"block",padding:intermediateCheckboxPadding,paddingTop:0,marginLeft:54,color:wonderBlocksTokens.color.offBlack64,[mediaQueries.smOrSmaller]:{padding:intermediateCheckboxPaddingPhone,paddingTop:0}}});var Choice$1 = React__namespace.forwardRef(function ChoiceWithRef(props,ref){return jsxRuntimeExports.jsx(Choice,{...props,forwardedRef:ref})});
|
|
1803
1805
|
|
|
1804
1806
|
const ChoiceNoneAbove=function({content,forwardedRef,showContent=true,...rest}){const{strings}=usePerseusI18n();const choiceProps={...rest,content:showContent?content:jsxRuntimeExports.jsx(Renderer,{content:strings.noneOfTheAbove,strings:strings},"noneOfTheAboveRenderer")};return jsxRuntimeExports.jsx(Choice$1,{...choiceProps,ref:forwardedRef})};var ChoiceNoneAbove$1 = React__namespace.forwardRef(function ChoiceNoneAboveWithRef(props,ref){return jsxRuntimeExports.jsx(ChoiceNoneAbove,{...props,forwardedRef:ref})});
|
|
1805
1807
|
|
|
1806
|
-
const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;function getInstructionsText(multipleSelect,countChoices,numCorrect,strings){if(multipleSelect){if(perseusCore.usesNumCorrect(multipleSelect,!!countChoices,numCorrect)){return strings.chooseNumAnswers({numCorrect:String(numCorrect)})}return strings.chooseAllAnswers}return strings.chooseOneAnswer}const BaseRadio=function({apiOptions,reviewModeRubric,reviewMode,choices,editMode=false,multipleSelect=false,labelWrap,countChoices,numCorrect,isLastUsedWidget,onChange,registerFocusFunction}){const{strings}=usePerseusI18n();const prevReviewModeRubric=React.useRef();const choiceRefs=React.useRef([]);React.useEffect(()=>{if(apiOptions.canScrollPage&&isLastUsedWidget&&reviewModeRubric&&!prevReviewModeRubric.current){const checkedIndex=choices.findIndex(c=>c.checked);if(checkedIndex>=0){const ref=choiceRefs.current[checkedIndex];const anyNode=ReactDOM__namespace.default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){scrollElementIntoView(buttonNode);}}}prevReviewModeRubric.current=reviewModeRubric;},[apiOptions,choices,isLastUsedWidget,reviewModeRubric]);function updateChoice(choiceIndex,newValues){let newCheckedList;if(newValues.checked&&!multipleSelect){newCheckedList=choices.map(_=>false);}else {newCheckedList=choices.map(c=>c.checked);}newCheckedList[choiceIndex]=newValues.checked;onChange({checked:newCheckedList});}registerFocusFunction?.(choiceIndex=>{const ref=choiceRefs.current[choiceIndex||0];const anyNode=ReactDOM__namespace.default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){buttonNode.focus();}else {return false}return true});const isMobile=apiOptions.isMobile;const firstChoiceHighlighted=choices[0].highlighted;const lastChoiceHighlighted=choices[choices.length-1].highlighted;const className=classNames__default.default("perseus-widget-radio",!editMode&&"perseus-rendered-radio",aphrodite.css(styles$p.radio,styles$p.responsiveRadioContainer,firstChoiceHighlighted&&isMobile&&styles$p.radioContainerFirstHighlighted,lastChoiceHighlighted&&isMobile&&styles$p.radioContainerLastHighlighted));const instructionsClassName=classNames__default.default("instructions",aphrodite.css(styles$p.instructions,isMobile&&styles$p.instructionsMobile));const instructions=getInstructionsText(multipleSelect,countChoices,numCorrect,strings);const responsiveClassName=aphrodite.css(styles$p.responsiveFieldset);const fieldset=jsxRuntimeExports.jsxs("fieldset",{className:`perseus-widget-radio-fieldset ${responsiveClassName}`,children:[jsxRuntimeExports.jsx("legend",{className:"perseus-sr-only",children:instructions}),jsxRuntimeExports.jsx("div",{className:instructionsClassName,"aria-hidden":"true",children:instructions}),jsxRuntimeExports.jsx("ul",{className:className,style:{listStyle:"none"},children:choices.map((choice,i)=>{let Element=Choice$1;const ref=React__namespace.createRef();choiceRefs.current[i]=ref;const elementProps={apiOptions:apiOptions,multipleSelect:multipleSelect,checked:choice.checked,previouslyAnswered:choice.previouslyAnswered,reviewMode,correct:choice.correct,rationale:choice.rationale,content:choice.content,disabled:apiOptions.readOnly||choice.disabled,showCorrectness:reviewMode||!!choice.showCorrectness,showRationale:choice.hasRationale&&(reviewMode||choice.showRationale),pos:i,onChange:newValues=>{if(editMode){return}updateChoice(i,newValues);}};if(choice.isNoneOfTheAbove){Element=ChoiceNoneAbove$1;___default.default.extend(elementProps,{showContent:choice.revealNoneOfTheAbove});}const nextChoice=choices[i+1];const nextChoiceHighlighted=!!nextChoice&&nextChoice.highlighted;const aphroditeClassName=checked=>{return aphrodite.css(styles$p.item,styles$p.responsiveItem,checked&&styles$p.selectedItem,checked&&choice.highlighted&&styles$p.aboveBackdrop,checked&&choice.highlighted&&apiOptions.isMobile&&styles$p.aboveBackdropMobile,nextChoiceHighlighted&&apiOptions.isMobile&&styles$p.nextHighlighted)};aphroditeClassName(true);let correctnessClass;if(reviewMode&&reviewModeRubric){correctnessClass=reviewModeRubric.choices[i].correct?ClassNames.CORRECT:ClassNames.INCORRECT;}const className=classNames__default.default(aphroditeClassName(choice.checked),ClassNames.RADIO.OPTION,choice.checked&&ClassNames.RADIO.SELECTED,correctnessClass);let listElem=null;let clickHandler;if(editMode){clickHandler=e=>{let elem=e.target;while(elem&&elem!==listElem){if(elem.getAttribute("data-is-radio-icon")){updateChoice(i,{checked:!choice.checked});return}elem=elem.parentNode;}};}return jsxRuntimeExports.jsx("li",{ref:e=>listElem=e,className:className,onClick:clickHandler,onTouchStart:labelWrap?undefined:captureScratchpadTouchStart$1,children:jsxRuntimeExports.jsx(Element,{...elementProps,ref:ref})},
|
|
1808
|
+
const{captureScratchpadTouchStart: captureScratchpadTouchStart$1}=Util;function getInstructionsText(multipleSelect,countChoices,numCorrect,strings){if(multipleSelect){if(perseusCore.usesNumCorrect(multipleSelect,!!countChoices,numCorrect)){return strings.chooseNumAnswers({numCorrect:String(numCorrect)})}return strings.chooseAllAnswers}return strings.chooseOneAnswer}const BaseRadio=function({apiOptions,reviewModeRubric,reviewMode,choices,editMode=false,multipleSelect=false,labelWrap,countChoices,numCorrect,isLastUsedWidget,onChange,registerFocusFunction}){const{strings}=usePerseusI18n();const prevReviewModeRubric=React.useRef();const choiceRefs=React.useRef([]);React.useEffect(()=>{if(apiOptions.canScrollPage&&isLastUsedWidget&&reviewModeRubric&&!prevReviewModeRubric.current){const checkedIndex=choices.findIndex(c=>c.checked);if(checkedIndex>=0){const ref=choiceRefs.current[checkedIndex];const anyNode=ReactDOM__namespace.default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){scrollElementIntoView(buttonNode);}}}prevReviewModeRubric.current=reviewModeRubric;},[apiOptions,choices,isLastUsedWidget,reviewModeRubric]);function updateChoice(choiceIndex,newValues){let newCheckedList;if(newValues.checked&&!multipleSelect){newCheckedList=choices.map(_=>false);}else {newCheckedList=choices.map(c=>c.checked);}newCheckedList[choiceIndex]=newValues.checked;onChange({checked:newCheckedList});}registerFocusFunction?.(choiceIndex=>{const ref=choiceRefs.current[choiceIndex||0];const anyNode=ReactDOM__namespace.default.findDOMNode(ref.current);const buttonNode=anyNode;if(buttonNode){buttonNode.focus();}else {return false}return true});const isMobile=apiOptions.isMobile;const firstChoiceHighlighted=choices[0].highlighted;const lastChoiceHighlighted=choices[choices.length-1].highlighted;const className=classNames__default.default("perseus-widget-radio",!editMode&&"perseus-rendered-radio",aphrodite.css(styles$p.radio,styles$p.responsiveRadioContainer,firstChoiceHighlighted&&isMobile&&styles$p.radioContainerFirstHighlighted,lastChoiceHighlighted&&isMobile&&styles$p.radioContainerLastHighlighted));const instructionsClassName=classNames__default.default("instructions",aphrodite.css(styles$p.instructions,isMobile&&styles$p.instructionsMobile));const instructions=getInstructionsText(multipleSelect,countChoices,numCorrect,strings);const responsiveClassName=aphrodite.css(styles$p.responsiveFieldset);const fieldset=jsxRuntimeExports.jsxs("fieldset",{className:`perseus-widget-radio-fieldset ${responsiveClassName}`,children:[jsxRuntimeExports.jsx("legend",{className:"perseus-sr-only",children:instructions}),jsxRuntimeExports.jsx("div",{className:instructionsClassName,"aria-hidden":"true",children:instructions}),jsxRuntimeExports.jsx("ul",{className:className,style:{listStyle:"none"},children:choices.map((choice,i)=>{let Element=Choice$1;const ref=React__namespace.createRef();choiceRefs.current[i]=ref;const elementProps={id:choice.id,apiOptions:apiOptions,multipleSelect:multipleSelect,checked:choice.checked,previouslyAnswered:choice.previouslyAnswered,reviewMode,correct:choice.correct,rationale:choice.rationale,content:choice.content,disabled:apiOptions.readOnly||choice.disabled,showCorrectness:reviewMode||!!choice.showCorrectness,showRationale:choice.hasRationale&&(reviewMode||choice.showRationale),pos:i,onChange:newValues=>{if(editMode){return}updateChoice(i,newValues);}};if(choice.isNoneOfTheAbove){Element=ChoiceNoneAbove$1;___default.default.extend(elementProps,{showContent:choice.revealNoneOfTheAbove});}const nextChoice=choices[i+1];const nextChoiceHighlighted=!!nextChoice&&nextChoice.highlighted;const aphroditeClassName=checked=>{return aphrodite.css(styles$p.item,styles$p.responsiveItem,checked&&styles$p.selectedItem,checked&&choice.highlighted&&styles$p.aboveBackdrop,checked&&choice.highlighted&&apiOptions.isMobile&&styles$p.aboveBackdropMobile,nextChoiceHighlighted&&apiOptions.isMobile&&styles$p.nextHighlighted)};aphroditeClassName(true);let correctnessClass;if(reviewMode&&reviewModeRubric){correctnessClass=reviewModeRubric.choices[i].correct?ClassNames.CORRECT:ClassNames.INCORRECT;}const className=classNames__default.default(aphroditeClassName(choice.checked),ClassNames.RADIO.OPTION,choice.checked&&ClassNames.RADIO.SELECTED,correctnessClass);let listElem=null;let clickHandler;if(editMode){clickHandler=e=>{let elem=e.target;while(elem&&elem!==listElem){if(elem.getAttribute("data-is-radio-icon")){updateChoice(i,{checked:!choice.checked});return}elem=elem.parentNode;}};}return jsxRuntimeExports.jsx("li",{ref:e=>listElem=e,className:className,onClick:clickHandler,onTouchStart:labelWrap?undefined:captureScratchpadTouchStart$1,children:jsxRuntimeExports.jsx(Element,{...elementProps,ref:ref})},choice.id)})})]});return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styles$p.responsiveContainer),children:fieldset})};const styles$p=aphrodite.StyleSheet.create({instructions:{display:"block",color:gray17,fontSize:14,lineHeight:1.25,fontFamily:"inherit",fontStyle:"normal",fontWeight:"bold",marginBottom:16},instructionsMobile:{fontSize:18,[mediaQueries.smOrSmaller]:{fontSize:16},[mediaQueries.xl]:{fontSize:20}},radio:{padding:0},responsiveRadioContainer:{borderBottom:`1px solid ${radioBorderColor$1}`,borderTop:`1px solid ${radioBorderColor$1}`,width:"auto",[mediaQueries.smOrSmaller]:{marginLeft:negativePhoneMargin,marginRight:negativePhoneMargin}},radioContainerFirstHighlighted:{borderTop:`1px solid rgba(0, 0, 0, 0)`},radioContainerLastHighlighted:{borderBottom:`1px solid rgba(0, 0, 0, 0)`},item:{marginLeft:20},responsiveItem:{marginLeft:0,padding:0,":not(:last-child)":{borderBottom:`1px solid ${radioBorderColor$1}`}},selectedItem:{background:"white"},aboveBackdrop:{position:"relative",zIndex:1062},aboveBackdropMobile:{boxShadow:"0 0 4px 0 rgba(0, 0, 0, 0.2),"+"0 0 2px 0 rgba(0, 0, 0, 0.1)",":not(:last-child)":{borderBottom:`1px solid rgba(0, 0, 0, 0)`}},nextHighlighted:{":not(:last-child)":{borderBottom:`1px solid rgba(0, 0, 0, 0)`}},responsiveContainer:{overflow:"auto",marginLeft:negativePhoneMargin,paddingLeft:phoneMargin},responsiveFieldset:{paddingRight:phoneMargin,minWidth:"auto"}});
|
|
1807
1809
|
|
|
1808
|
-
let Radio$2 = class Radio extends React__namespace.Component{focus(choiceIndex){if(this.focusFunction){return this.focusFunction(choiceIndex)}return false}registerFocusFunction(fun){this.focusFunction=fun;}getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const{choices}=this.props;const{strings}=this.context;let choiceStates;if(this.props.static){choiceStates=choices.map(choice=>({selected:!!choice.correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.showSolutions==="all"){choiceStates=choices.map(({correct})=>({selected:!!correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.choiceStates){choiceStates=this.props.choiceStates;}else if(this.props.values){choiceStates=this.props.values.map(val=>({selected:val,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}else {choiceStates=choices.map(()=>({selected:false,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}const choicesProp=choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,highlighted,previouslyAnswered}=choiceStates[i];const reviewChoice=this.props.reviewModeRubric?.choices[i];return {content:this._renderRenderer(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:this._renderRenderer(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(this.props.questionCompleted&&selected),highlighted,previouslyAnswered:previouslyAnswered}});return jsxRuntimeExports.jsx(BaseRadio,{labelWrap:true,multipleSelect:this.props.multipleSelect,countChoices:this.props.countChoices,numCorrect:this.props.numCorrect,choices:choicesProp,onChange:this.updateChoices,reviewModeRubric:this.props.reviewModeRubric,reviewMode:this.props.reviewMode,deselectEnabled:this.props.deselectEnabled,apiOptions:this.props.apiOptions,isLastUsedWidget:this.props.isLastUsedWidget,registerFocusFunction:i=>this.registerFocusFunction(i)})}constructor(...args){super(...args),this._renderRenderer=(content="")=>{let nextPassageRefId=1;const widgets={};const modContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(match,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;widgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return jsxRuntimeExports.jsx(Renderer,{content:modContent,widgets:widgets,findExternalWidgets:this.props.findWidgets,alwaysUpdate:true,linterContext:{...this.props.linterContext,blockHighlight:true},strings:this.context.strings},"choiceContentRenderer")},this.updateChoices=newValueLists=>{const{choiceStates,choices}=this.props;const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{choiceState.selected=newValueLists.checked[i];});this.props.onChange({choiceStates:newChoiceStates});this.props.trackInteraction();};}};Radio$2.contextType=PerseusI18nContext;Radio$2.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:PerseusLinter.linterContextDefault,showSolutions:"none"};
|
|
1810
|
+
let Radio$2 = class Radio extends React__namespace.Component{focus(choiceIndex){if(this.focusFunction){return this.focusFunction(choiceIndex)}return false}registerFocusFunction(fun){this.focusFunction=fun;}getPromptJSON(){return getPromptJSON$q(this.props,this.props.userInput)}render(){const{choices}=this.props;const{strings}=this.context;let choiceStates;if(this.props.static){choiceStates=choices.map(choice=>({selected:!!choice.correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.showSolutions==="all"){choiceStates=choices.map(({correct})=>({selected:!!correct,crossedOut:false,readOnly:true,highlighted:false,rationaleShown:true,correctnessShown:true,previouslyAnswered:false}));}else if(this.props.choiceStates){choiceStates=this.props.choiceStates;}else if(this.props.values){choiceStates=this.props.values.map(val=>({selected:val,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}else {choiceStates=choices.map(()=>({selected:false,crossedOut:false,readOnly:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false}));}const choicesProp=choices.map((choice,i)=>{const content=choice.isNoneOfTheAbove&&!choice.content?strings.noneOfTheAbove:choice.content;const{selected,rationaleShown,correctnessShown,readOnly,highlighted,previouslyAnswered}=choiceStates[i];const reviewChoice=this.props.reviewModeRubric?.choices[i];return {id:choice.id,content:this._renderRenderer(content),checked:selected,correct:choice.correct===undefined?!!reviewChoice&&!!reviewChoice.correct:choice.correct,disabled:readOnly,hasRationale:!!choice.rationale,rationale:this._renderRenderer(choice.rationale),showRationale:rationaleShown,showCorrectness:correctnessShown,isNoneOfTheAbove:!!choice.isNoneOfTheAbove,revealNoneOfTheAbove:!!(this.props.questionCompleted&&selected),highlighted,previouslyAnswered:previouslyAnswered}});return jsxRuntimeExports.jsx(BaseRadio,{labelWrap:true,multipleSelect:this.props.multipleSelect,countChoices:this.props.countChoices,numCorrect:this.props.numCorrect,choices:choicesProp,onChange:this.updateChoices,reviewModeRubric:this.props.reviewModeRubric,reviewMode:this.props.reviewMode,deselectEnabled:this.props.deselectEnabled,apiOptions:this.props.apiOptions,isLastUsedWidget:this.props.isLastUsedWidget,registerFocusFunction:i=>this.registerFocusFunction(i)})}constructor(...args){super(...args),this._renderRenderer=(content="")=>{let nextPassageRefId=1;const widgets={};const modContent=content.replace(/\{\{passage-ref (\d+) (\d+)(?: "([^"]*)")?\}\}/g,(match,passageNum,refNum,summaryText)=>{const widgetId="passage-ref "+nextPassageRefId;nextPassageRefId++;widgets[widgetId]={type:"passage-ref",graded:false,options:{passageNumber:parseInt(passageNum),referenceNumber:parseInt(refNum),summaryText:summaryText},version:PassageRef$1.version};return "[["+Util.snowman+" "+widgetId+"]]"});return jsxRuntimeExports.jsx(Renderer,{content:modContent,widgets:widgets,findExternalWidgets:this.props.findWidgets,alwaysUpdate:true,linterContext:{...this.props.linterContext,blockHighlight:true},strings:this.context.strings},"choiceContentRenderer")},this.updateChoices=newValueLists=>{const{choiceStates,choices}=this.props;const newChoiceStates=choiceStates?choiceStates.map(state=>({...state})):choices.map(()=>({selected:false,highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}));newChoiceStates.forEach((choiceState,i)=>{choiceState.selected=newValueLists.checked[i];});this.props.onChange({choiceStates:newChoiceStates});this.props.trackInteraction();};}};Radio$2.contextType=PerseusI18nContext;Radio$2.defaultProps={choices:[],multipleSelect:false,countChoices:false,deselectEnabled:false,linterContext:PerseusLinter.linterContextDefault,showSolutions:"none"};
|
|
1809
1811
|
|
|
1810
1812
|
function initChoiceStates(choices){return choices.map(()=>({highlighted:false,rationaleShown:false,correctnessShown:false,previouslyAnswered:false,readOnly:false}))}let Radio$1 = class Radio extends Radio$2{UNSAFE_componentWillUpdate(nextProps){if(!___default.default.isEqual(nextProps.choices,this.props.choices)){this.setState({choiceStates:initChoiceStates(nextProps.choices)});}}getSerializedState(){const{userInput:_,...rest}=this._mergePropsAndState();return {...rest}}_handleChange(arg){const newChoiceStates=arg.choiceStates;if(newChoiceStates){this.setState({choiceStates:newChoiceStates.map(choiceState=>{const{selected:_,...rest}=choiceState;return {...rest}})},()=>{const props=this._mergePropsAndState();const mergedProps={...props,choiceStates:perseusCore.deepClone(props.choiceStates||[]).map((choiceState,index)=>{return {...choiceState,selected:newChoiceStates[index].selected}})};const unshuffledUserInput=getUserInputFromSerializedState$f(mergedProps);this.props.handleUserInput(unshuffledUserInput);});}else {throw new Error("unhandled onChange call in Radio!")}}_mergePropsAndState(){return {...this.props,choiceStates:this.state.choiceStates?.map((choiceState,index)=>{const choice=this.props.choices[index];const selected=this.props.userInput?.choicesSelected[choice.originalIndex];return {...choiceState,selected}}),onChange:arg=>this._handleChange(arg)}}focus(choiceIndex){if(this.radioRef.current?.focus){return this.radioRef.current.focus(choiceIndex)}return false}render(){const props=this._mergePropsAndState();return this.ffIsOn?jsxRuntimeExports.jsx(Radio$3,{...props}):jsxRuntimeExports.jsx(Radio$2,{ref:this.radioRef,...props})}constructor(props){super(props),this.ffIsOn=false,this.radioRef=React__namespace.createRef(),this.state={choiceStates:[]};this.ffIsOn=props.apiOptions.flags?.["new-radio-widget"]??false;this.state={choiceStates:initChoiceStates(props.choices)};}};
|
|
1811
1813
|
|
|
1812
|
-
const _choiceTransform=(widgetOptions,strings)=>{const _maybeRandomize=function(array){return widgetOptions.randomize?perseusCore.randomizeArrayElements(array):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=>___default.default.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$
|
|
1814
|
+
const _choiceTransform=(widgetOptions,strings)=>{const _maybeRandomize=function(array){return widgetOptions.randomize?perseusCore.randomizeArrayElements(array):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=>___default.default.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$1=(widgetOptions,strings)=>{const choices=_choiceTransform(widgetOptions,strings);const{hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,numCorrect}=widgetOptions;return {numCorrect:numCorrect,hasNoneOfTheAbove,multipleSelect,countChoices,deselectEnabled,choices,selectedChoices:___default.default.pluck(choices,"correct")}};function getStartUserInput$g(options){return {choicesSelected:options.choices.map(()=>false)}}function getCorrectUserInput$6(options){return {choicesSelected:options.choices.map(option=>!!option.correct)}}var Radio = {name:"radio",displayName:"Radio / Multiple choice",widget:Radio$1,transform: transform$1,staticTransform:transform$1,getStartUserInput: getStartUserInput$g,getCorrectUserInput: getCorrectUserInput$6,version:perseusCore.radioLogic.version,isLintable:true,getUserInputFromSerializedState:serializedState=>{return getUserInputFromSerializedState$f(serializedState,true)}};
|
|
1813
1815
|
|
|
1814
1816
|
var basicWidgets = [Radio,InputNumber$1,NumericInput$1,Expression$1];
|
|
1815
1817
|
|
|
@@ -1817,7 +1819,7 @@ const{radioBorderColor,checkedColor,circleSize,radioMarginWidth}=constants;var s
|
|
|
1817
1819
|
|
|
1818
1820
|
const getPromptJSON$n=renderProps=>{return {type:"categorizer",options:{items:renderProps.items,categories:renderProps.categories},userInput:{itemToCategoryMapping:renderProps.userInput.values}}};
|
|
1819
1821
|
|
|
1820
|
-
class Categorizer extends React__namespace.Component{getSerializedState(){const{userInput,...rest}=this.props;return {...rest,values:userInput.values}}getPromptJSON(){return getPromptJSON$n(this.props)}_handleUserInput(itemNum,catNum){const values=[...this.props.userInput.values];values[itemNum]=catNum;this.props.handleUserInput({values});this.props.trackInteraction();}render(){const self=this;const isMobile=this.props.apiOptions.isMobile;let indexedItems=this.props.items.map((item,n)=>[item,n]);if(this.props.randomizeItems){indexedItems=perseusCore.shuffle(indexedItems,this.props.problemNum);}const table=jsxRuntimeExports.jsxs("table",{className:"categorizer-table "+aphrodite.css(styles$o.mobileTable),children:[jsxRuntimeExports.jsx("thead",{children:jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$o.emptyHeaderCell)}),this.props.categories.map((category,i)=>{return jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$o.header),children:jsxRuntimeExports.jsx(Renderer,{content:category,linterContext:this.props.linterContext,strings:this.context.strings})},i)})]})}),jsxRuntimeExports.jsx("tbody",{children:indexedItems.map(indexedItem=>{const item=indexedItem[0];const itemNum=indexedItem[1];const uniqueId=self.state.uniqueId+"_"+itemNum;return jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx(Renderer,{content:item,linterContext:this.props.linterContext,strings:this.context.strings})}),self.props.categories.map((catName,catNum)=>{const selected=self.props.userInput.values[itemNum]===catNum;return jsxRuntimeExports.jsx("td",{className:"category "+aphrodite.css(styles$o.cell),children:jsxRuntimeExports.jsxs("div",{role:"button","aria-label":catName,onClick:()=>this._handleUserInput(itemNum,catNum),children:[isMobile&&jsxRuntimeExports.jsx("input",{type:"radio",name:uniqueId,className:aphrodite.css(sharedStyles.responsiveInput,sharedStyles.responsiveRadioInput),checked:selected,onChange:()=>this._handleUserInput(itemNum,catNum),onClick:e=>e.stopPropagation()}),!isMobile&&jsxRuntimeExports.jsx("span",{className:aphrodite.css(styles$o.radioSpan,selected&&styles$o.checkedRadioSpan,this.props.static&&selected&&styles$o.staticCheckedRadioSpan),children:selected?jsxRuntimeExports.jsx(InlineIcon,{...iconCircle}):jsxRuntimeExports.jsx(InlineIcon,{...iconCircleThin})})]})},catNum)})]},itemNum)})})]});const extraClassNames=classNames__default.default({"categorizer-container":true,"static-mode":this.props.static});const inlineStyles=this.props.apiOptions.isMobile?[styles$o.fullBleedContainer]:[];return jsxRuntimeExports.jsx("div",{className:extraClassNames+" "+aphrodite.css(...inlineStyles),children:table})}constructor(...args){super(...args),this.state={uniqueId:___default.default.uniqueId("perseus_radio_")};}}Categorizer.contextType=PerseusI18nContext;Categorizer.defaultProps={items:[],categories:[],linterContext:PerseusLinter.linterContextDefault,userInput:{values:[]}};const styles$o=aphrodite.StyleSheet.create({mobileTable:{[mediaQueries.smOrSmaller]:{minWidth:"auto"}},fullBleedContainer:{[mediaQueries.mdOrSmaller]:{marginLeft:-16,marginRight:-16,overflowX:"auto"}},header:{textAlign:"center",verticalAlign:"bottom"},cell:{textAlign:"center",padding:0,color:"#ccc",verticalAlign:"middle"},emptyHeaderCell:{backgroundColor:"inherit",borderBottom:"2px solid #ccc"},radioSpan:{fontSize:30,paddingRight:3,":hover":{color:"#999"}},checkedRadioSpan:{color:"#333"},staticCheckedRadioSpan:{color:"#888"}});function getUserInputFromSerializedState$e(serializedState){return {values:serializedState.values}}function getCorrectUserInput$5(options){return {values:options.values}}function getStartUserInput$f(){return {values:[]}}
|
|
1822
|
+
class Categorizer extends React__namespace.Component{getSerializedState(){const{userInput,...rest}=this.props;return {...rest,values:userInput.values}}getPromptJSON(){return getPromptJSON$n(this.props)}_handleUserInput(itemNum,catNum){const values=[...this.props.userInput.values];values[itemNum]=catNum;this.props.handleUserInput({values});this.props.trackInteraction();}render(){const self=this;const isMobile=this.props.apiOptions.isMobile;let indexedItems=this.props.items.map((item,n)=>[item,n]);if(this.props.randomizeItems){indexedItems=perseusCore.shuffle(indexedItems,this.props.problemNum);}const table=jsxRuntimeExports.jsxs("table",{className:"categorizer-table "+aphrodite.css(styles$o.mobileTable),children:[jsxRuntimeExports.jsx("thead",{children:jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{className:aphrodite.css(styles$o.emptyHeaderCell)}),this.props.categories.map((category,i)=>{return jsxRuntimeExports.jsx("th",{className:aphrodite.css(styles$o.header),children:jsxRuntimeExports.jsx(Renderer,{content:category,linterContext:this.props.linterContext,strings:this.context.strings})},i)})]})}),jsxRuntimeExports.jsx("tbody",{children:indexedItems.map(indexedItem=>{const item=indexedItem[0];const itemNum=indexedItem[1];const uniqueId=self.state.uniqueId+"_"+itemNum;return jsxRuntimeExports.jsxs("tr",{children:[jsxRuntimeExports.jsx("td",{children:jsxRuntimeExports.jsx(Renderer,{content:item,linterContext:this.props.linterContext,strings:this.context.strings})}),self.props.categories.map((catName,catNum)=>{const selected=self.props.userInput.values[itemNum]===catNum;return jsxRuntimeExports.jsx("td",{className:"category "+aphrodite.css(styles$o.cell),children:jsxRuntimeExports.jsxs("div",{role:"button","aria-label":catName,onClick:()=>this._handleUserInput(itemNum,catNum),children:[isMobile&&jsxRuntimeExports.jsx("input",{type:"radio",name:uniqueId,className:aphrodite.css(sharedStyles.responsiveInput,sharedStyles.responsiveRadioInput),checked:selected,onChange:()=>this._handleUserInput(itemNum,catNum),onClick:e=>e.stopPropagation()}),!isMobile&&jsxRuntimeExports.jsx("span",{className:aphrodite.css(styles$o.radioSpan,selected&&styles$o.checkedRadioSpan,this.props.static&&selected&&styles$o.staticCheckedRadioSpan),children:selected?jsxRuntimeExports.jsx(InlineIcon,{...iconCircle}):jsxRuntimeExports.jsx(InlineIcon,{...iconCircleThin})})]})},catNum)})]},itemNum)})})]});const extraClassNames=classNames__default.default({"categorizer-container":true,"static-mode":this.props.static});const inlineStyles=this.props.apiOptions.isMobile?[styles$o.fullBleedContainer]:[];return jsxRuntimeExports.jsx("div",{className:extraClassNames+" "+aphrodite.css(...inlineStyles),children:table})}constructor(...args){super(...args),this.state={uniqueId:___default.default.uniqueId("perseus_radio_")};}}Categorizer.contextType=PerseusI18nContext;Categorizer.defaultProps={items:[],categories:[],linterContext:PerseusLinter.linterContextDefault,userInput:{values:[]}};const styles$o=aphrodite.StyleSheet.create({mobileTable:{[mediaQueries.smOrSmaller]:{minWidth:"auto"}},fullBleedContainer:{[mediaQueries.mdOrSmaller]:{marginLeft:-16,marginRight:-16,overflowX:"auto"}},header:{textAlign:"center",verticalAlign:"bottom"},cell:{textAlign:"center",padding:0,color:"#ccc",verticalAlign:"middle"},emptyHeaderCell:{backgroundColor:"inherit",borderBottom:"2px solid #ccc"},radioSpan:{fontSize:30,paddingRight:3,":hover":{color:"#999"}},checkedRadioSpan:{color:"#333"},staticCheckedRadioSpan:{color:"#888"}});function getUserInputFromSerializedState$e(serializedState){return {values:serializedState.values}}function getCorrectUserInput$5(options){return {values:options.values}}function getStartUserInput$f(){return {values:[]}}var Categorizer$1 = {name:"categorizer",displayName:"Categorizer",hidden:true,widget:Categorizer,getUserInputFromSerializedState: getUserInputFromSerializedState$e,getCorrectUserInput: getCorrectUserInput$5,getStartUserInput: getStartUserInput$f,isLintable:true};
|
|
1821
1823
|
|
|
1822
1824
|
const isFileProtocol=protocol=>{if(protocol&&protocol.toLowerCase()==="file:"){return true}return false};
|
|
1823
1825
|
|
|
@@ -1827,7 +1829,7 @@ const getUnsupportedPromptJSON=(widgetType,message="")=>{return {type:widgetType
|
|
|
1827
1829
|
|
|
1828
1830
|
const getPromptJSON$m=()=>{return getUnsupportedPromptJSON("cs-program")};
|
|
1829
1831
|
|
|
1830
|
-
const{updateQueryString: updateQueryString$1}=Util;function getUrlFromProgramID$1(programID){const{InitialRequestUrl}=getDependencies();const path="/computer-programming/program/"+`${programID}/embedded?embed=yes&author=no`;if(isFileProtocol(InitialRequestUrl.protocol)){return `https://khanacademy.org${path}`}return toAbsoluteUrl(path)}class CSProgram extends React__namespace.Component{componentDidMount(){$__default.default(window).on("message",this.handleMessageEvent);}componentWillUnmount(){$__default.default(window).off("message",this.handleMessageEvent);}getPromptJSON(){return getPromptJSON$m()}render(){if(!this.props.programID){return jsxRuntimeExports.jsx("div",{})}let styleContainer=false;let url=getUrlFromProgramID$1(this.props.programID);let className;const style={height:this.props.height,width:"100%"};if(this.props.showEditor){url+="&editor=yes";className="perseus-scratchpad-editor";}else {url+=`&editor=no&width=${articleMaxWidthInPx}`;className="perseus-scratchpad";if(this.props.programType!=="webpage"){styleContainer=true;}}if(this.props.showButtons){url+="&buttons=yes";style.height+=67;}else {url+="&buttons=no";}if(this.props.settings){const settings={};___default.default.each(this.props.settings,function(setting){if(setting.name&&setting.value){settings[setting.name]=setting.value;}});url=updateQueryString$1(url,"settings",JSON.stringify(settings));}const sandboxOptions=["allow-popups","allow-same-origin","allow-scripts","allow-top-navigation"].join(" ");return jsxRuntimeExports.jsx("div",{className:aphrodite.css(
|
|
1832
|
+
const{updateQueryString: updateQueryString$1}=Util;function getUrlFromProgramID$1(programID){const{InitialRequestUrl}=getDependencies();const path="/computer-programming/program/"+`${programID}/embedded?embed=yes&author=no`;if(isFileProtocol(InitialRequestUrl.protocol)){return `https://khanacademy.org${path}`}return toAbsoluteUrl(path)}class CSProgram extends React__namespace.Component{componentDidMount(){$__default.default(window).on("message",this.handleMessageEvent);}componentWillUnmount(){$__default.default(window).off("message",this.handleMessageEvent);}getPromptJSON(){return getPromptJSON$m()}render(){if(!this.props.programID){return jsxRuntimeExports.jsx("div",{})}let styleContainer=false;let url=getUrlFromProgramID$1(this.props.programID);let className;const style={height:this.props.height,width:"100%"};if(this.props.showEditor){url+="&editor=yes";className="perseus-scratchpad-editor";}else {url+=`&editor=no&width=${articleMaxWidthInPx}`;className="perseus-scratchpad";if(this.props.programType!=="webpage"){styleContainer=true;}}if(this.props.showButtons){url+="&buttons=yes";style.height+=67;}else {url+="&buttons=no";}if(this.props.settings){const settings={};___default.default.each(this.props.settings,function(setting){if(setting.name&&setting.value){settings[setting.name]=setting.value;}});url=updateQueryString$1(url,"settings",JSON.stringify(settings));}const sandboxOptions=["allow-popups","allow-same-origin","allow-scripts","allow-top-navigation"].join(" ");return jsxRuntimeExports.jsx("div",{className:aphrodite.css(styleContainer&&styles$n.container),children:jsxRuntimeExports.jsx("iframe",{sandbox:sandboxOptions,src:url,style:style,className:className,allowFullScreen:true})})}constructor(...args){super(...args),this.handleMessageEvent=e=>{let data={};try{data=JSON.parse(e.originalEvent.data);}catch{return}if(___default.default.isUndefined(data.testsPassed)){return}const status=data.testsPassed?"correct":"incorrect";this.props.handleUserInput({status:status,message:data.message});};}}CSProgram.defaultProps={showEditor:false,showButtons:false,userInput:{status:"incomplete",message:null}};const styles$n=aphrodite.StyleSheet.create({container:{margin:"auto"}});function getUserInputFromSerializedState$d(serializedState){return {status:serializedState.status,message:serializedState.message}}function getStartUserInput$e(){return {status:"incomplete",message:null}}var CSProgram$1 = {name:"cs-program",displayName:"CS Program",widget:CSProgram,hidden:true,getStartUserInput: getStartUserInput$e,getUserInputFromSerializedState: getUserInputFromSerializedState$d};
|
|
1831
1833
|
|
|
1832
1834
|
const getPromptJSON$l=renderProps=>{return {type:"definition",definition:renderProps.definition,togglePrompt:renderProps.togglePrompt}};
|
|
1833
1835
|
|
|
@@ -1835,9 +1837,9 @@ class Definition extends React__namespace.Component{getPromptJSON(){return getPr
|
|
|
1835
1837
|
|
|
1836
1838
|
class DeprecatedStandin extends React__namespace.default.Component{render(){return jsxRuntimeExports.jsx("div",{style:{paddingTop:8,paddingBottom:8},children:jsxRuntimeExports.jsx(Banner__default.default,{text:this.context.strings.deprecatedStandin,kind:"info",layout:"full-width"})})}constructor(...args){super(...args),this.isWidget=true;}}DeprecatedStandin.contextType=PerseusI18nContext;var DeprecatedStandin$1 = {name:"deprecated-standin",displayName:"Deprecated Standin",widget:DeprecatedStandin,hidden:true};
|
|
1837
1839
|
|
|
1838
|
-
const getPromptJSON$k=renderProps=>{return {type:"dropdown",options:{items:renderProps.choices},userInput:{selectedIndex:renderProps.userInput.value-1}}};
|
|
1840
|
+
const getPromptJSON$k=renderProps=>{return {type:"dropdown",options:{items:renderProps.choices.map(choice=>choice.content)},userInput:{selectedIndex:renderProps.userInput.value-1}}};
|
|
1839
1841
|
|
|
1840
|
-
class Dropdown extends React__namespace.Component{getPromptJSON(){return getPromptJSON$k(this.props)}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,selected:userInput.value}}render(){const children=[jsxRuntimeExports.jsx(wonderBlocksDropdown.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(wonderBlocksDropdown.OptionItem,{value:String(i+1),label:jsxRuntimeExports.jsx(Renderer,{content:choice,strings:this.context.strings}),labelAsText:choice},String(i+1)))];return jsxRuntimeExports.jsx(wonderBlocksCore.Id,{children:dropdownId=>jsxRuntimeExports.jsxs(wonderBlocksCore.View,{onClick:e=>{e.stopPropagation();},onTouchStart:e=>{e.stopPropagation();},children:[this.props.visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.LabelLarge,{tag:"label",htmlFor:dropdownId,children:this.props.visibleLabel}),jsxRuntimeExports.jsx(wonderBlocksDropdown.SingleSelect,{id:dropdownId,placeholder:"",className:"perseus-dropdown",onChange:value=>this._handleChange(parseInt(value)),selectedValue:String(this.props.userInput.value),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__namespace.default.findDOMNode(this).focus();return true},this._handleChangeEvent=e=>{this._handleChange(parseInt(e.target.value));},this._handleChange=selected=>{this.props.trackInteraction();this.props.handleUserInput({value:selected});};}}Dropdown.contextType=PerseusI18nContext;Dropdown.defaultProps={choices:[],placeholder:"",apiOptions:ApiOptions.defaults,userInput:{value:0}};function
|
|
1842
|
+
class Dropdown extends React__namespace.Component{getPromptJSON(){return getPromptJSON$k(this.props)}getSerializedState(){const{userInput,choices,...rest}=this.props;return {...rest,choices:choices.map(choice=>choice.content),selected:userInput.value}}restoreSerializedState(state){return {state,choices:state.choices.map(content=>({content}))}}render(){const children=[jsxRuntimeExports.jsx(wonderBlocksDropdown.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(wonderBlocksDropdown.OptionItem,{value:String(i+1),label:jsxRuntimeExports.jsx(Renderer,{content:choice.content,strings:this.context.strings}),labelAsText:choice.content},String(i+1)))];return jsxRuntimeExports.jsx(wonderBlocksCore.Id,{children:dropdownId=>jsxRuntimeExports.jsxs(wonderBlocksCore.View,{onClick:e=>{e.stopPropagation();},onTouchStart:e=>{e.stopPropagation();},children:[this.props.visibleLabel&&jsxRuntimeExports.jsx(wonderBlocksTypography.LabelLarge,{tag:"label",htmlFor:dropdownId,children:this.props.visibleLabel}),jsxRuntimeExports.jsx(wonderBlocksDropdown.SingleSelect,{id:dropdownId,placeholder:"",className:"perseus-dropdown",onChange:value=>this._handleChange(parseInt(value)),selectedValue:String(this.props.userInput.value),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__namespace.default.findDOMNode(this).focus();return true},this._handleChangeEvent=e=>{this._handleChange(parseInt(e.target.value));},this._handleChange=selected=>{this.props.trackInteraction();this.props.handleUserInput({value:selected});};}}Dropdown.contextType=PerseusI18nContext;Dropdown.defaultProps={choices:[],placeholder:"",apiOptions:ApiOptions.defaults,userInput:{value:0}};function getUserInputFromSerializedState$c(serializedState){return {value:serializedState.selected}}function getStartUserInput$d(){return {value:0}}var Dropdown$1 = {name:"dropdown",displayName:"Drop down",widget:Dropdown,getStartUserInput: getStartUserInput$d,getUserInputFromSerializedState: getUserInputFromSerializedState$c};
|
|
1841
1843
|
|
|
1842
1844
|
const USAGE="Usage:\n"+" this.change({propName: 5}, callback);\n"+' this.change("propName", 5, callback);\n'+' this.change("propName")';const _changeMultiple=function(component,newProps,callback){const currProps=excludeDenylistKeys(component.props);const nextProps=___default.default.extend(currProps,newProps);component.props.onChange(nextProps,callback);};const _changeSingle=function(component,propName,value,callback){if(value===undefined){return ___default.default.partial(_changeSingle,component,propName)}const newProps={};newProps[propName]=value;_changeMultiple(component,newProps,callback);};const change=function(newPropsOrSinglePropName,propValue,callback){if(___default.default.isObject(newPropsOrSinglePropName)&&callback===undefined){callback=propValue;return _changeMultiple(this,newPropsOrSinglePropName,callback)}if(typeof newPropsOrSinglePropName==="string"){return _changeSingle(this,newPropsOrSinglePropName,propValue,callback)}throw new perseusCore.PerseusError("Invalid types sent to this.change(): "+___default.default.toArray(arguments).join()+"\n"+USAGE,perseusCore.Errors.Internal)};const propTypes={onChange:PropTypes__default.default.func.isRequired};
|
|
1843
1845
|
|
|
@@ -1851,7 +1853,7 @@ const getPromptJSON$j=renderProps=>{return {type:"explanation",showPrompt:render
|
|
|
1851
1853
|
|
|
1852
1854
|
function mediaQueryIsMatched(mediaQuery){if(typeof window.matchMedia!=="function"){return false}return window.matchMedia(mediaQuery).matches}class Explanation extends React__namespace.Component{componentDidMount(){this._mounted=true;}componentWillUnmount(){this._mounted=false;}getPromptJSON(){return getPromptJSON$j(this.props)}render(){const promptText=this.state.expanded?this.props.hidePrompt:this.props.showPrompt;const caretIcon=this.state.expanded?caretUp__default.default:caretDown__default.default;const allowTransition=this._mounted&&mediaQueryIsMatched("(prefers-reduced-motion: no-preference)");const buttonStyleOverrides={height:"auto",lineHeight:"inherit",marginLeft:"-2px",marginRight:"2px",paddingLeft:"2px"};const labelStyle={fontSize:"18px",lineHeight:"inherit","text-align":"left",marginRight:"-6px","white-space":"normal"};const contentStyling=[styles$l.content,this.state.expanded?styles$l.contentExpanded:styles$l.contentCollapsed,allowTransition&&(this.state.expanded?styles$l.transitionExpanded:styles$l.transitionCollapsed)];return jsxRuntimeExports.jsx(wonderBlocksCore.Id,{children:contentId=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button__default.default,{"aria-expanded":this.state.expanded,"aria-controls":contentId,endIcon:caretIcon,kind:"tertiary",labelStyle:labelStyle,onClick:this._onClick,size:"small",style:buttonStyleOverrides,children:promptText}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:contentId,style:contentStyling,"aria-hidden":!this.state.expanded,testId:"content-container",children:jsxRuntimeExports.jsx(wonderBlocksCore.View,{style:styles$l.contentWrapper,children:jsxRuntimeExports.jsx(Renderer,{apiOptions:this.props.apiOptions,content:this.props.explanation,widgets:this.props.widgets,linterContext:this.props.linterContext,strings:this.context.strings})})})]})})}constructor(...args){super(...args),this.isWidget=true,this.state={expanded:false},this._mounted=false,this.change=(...args)=>{return change.apply(this,args)},this._onClick=()=>{this.setState({expanded:!this.state.expanded});this.props.trackInteraction();};}}Explanation.contextType=PerseusI18nContext;Explanation.defaultProps={showPrompt:"Explain",hidePrompt:"Hide explanation",explanation:"explanation goes here\n\nmore explanation",widgets:{},linterContext:PerseusLinter.linterContextDefault};const leftBorderSpacing=23;const verticalContentPadding=10;const arrowHeight=14;const styles$l=aphrodite.StyleSheet.create({content:{borderLeft:"0px solid #ccc",display:"inline-grid",position:"relative"},contentCollapsed:{gridTemplateColumns:"0fr",gridTemplateRows:"0fr",marginBottom:0,marginTop:0,minWidth:"0",paddingBottom:0,visibility:"hidden"},contentExpanded:{borderLeftWidth:"5px",gridTemplateColumns:"1fr",gridTemplateRows:"1fr",marginLeft:-23,minWidth:"100%",paddingLeft:leftBorderSpacing,paddingBottom:verticalContentPadding,visibility:"visible",marginBottom:arrowHeight,marginTop:arrowHeight},contentWrapper:{overflow:"hidden"},transitionCollapsed:{transition:"all 0.25s step-end, grid-template-rows 0.25s, margin-top 0.25s, margin-bottom 0.25s, padding-bottom 0.25s"},transitionExpanded:{transition:"grid-template-rows 0.5s, margin-top 0.5s, margin-bottom 0.5s, padding-bottom 0.5s"}});var Explanation$1 = {name:"explanation",displayName:"Explanation",widget:Explanation,isLintable:true};
|
|
1853
1855
|
|
|
1854
|
-
class FreeResponse extends React__namespace.Component{isOverLimit(){return !this.props.allowUnlimitedCharacters&&this.characterCount()>this.props.characterLimit}renderCharacterCount(){if(this.props.allowUnlimitedCharacters){return null}const characterCountText=this.context.strings.characterCount({used:this.characterCount(),num:this.props.characterLimit});return jsxRuntimeExports.jsx(wonderBlocksCore.View,{children:jsxRuntimeExports.jsxs(wonderBlocksCore.Text,{role:"status",style:[styles$k.characterCountText,this.isOverLimit()?styles$k.overCharacterLimit:undefined],children:[this.isOverLimit()&&jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{icon:warningCircleIcon__default.default,size:"small",style:styles$k.warningCircleIcon}),characterCountText]})})}render(){return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:styles$k.container,className:"free-response",children:[jsxRuntimeExports.jsx(wonderBlocksLabeledField.LabeledField,{label:jsxRuntimeExports.jsx(wonderBlocksCore.View,{className:"free-response-question",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.question,strings:this.context.strings})}),field:jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{error:this.isOverLimit(),onChange:this._handleUserInput,placeholder:this.props.placeholder,style:styles$k.textarea,value:this.props.userInput.currentValue})
|
|
1856
|
+
class FreeResponse extends React__namespace.Component{isOverLimit(){return !this.props.allowUnlimitedCharacters&&this.characterCount()>this.props.characterLimit}renderCharacterCount(){if(this.props.allowUnlimitedCharacters){return null}const characterCountText=this.context.strings.characterCount({used:this.characterCount(),num:this.props.characterLimit});return jsxRuntimeExports.jsx(wonderBlocksCore.View,{children:jsxRuntimeExports.jsxs(wonderBlocksCore.Text,{role:"status",style:[styles$k.characterCountText,this.isOverLimit()?styles$k.overCharacterLimit:undefined],children:[this.isOverLimit()&&jsxRuntimeExports.jsx(wonderBlocksIcon.PhosphorIcon,{icon:warningCircleIcon__default.default,size:"small",style:styles$k.warningCircleIcon}),characterCountText]})})}render(){return jsxRuntimeExports.jsxs(wonderBlocksCore.View,{style:styles$k.container,className:"free-response",children:[jsxRuntimeExports.jsx(wonderBlocksLabeledField.LabeledField,{label:jsxRuntimeExports.jsx(wonderBlocksCore.View,{className:"free-response-question",children:jsxRuntimeExports.jsx(Renderer,{content:this.props.question,strings:this.context.strings})}),field:jsxRuntimeExports.jsx(wonderBlocksForm.TextArea,{error:this.isOverLimit(),onChange:this._handleUserInput,placeholder:this.props.placeholder,style:styles$k.textarea,value:this.props.userInput.currentValue})}),this.renderCharacterCount()]})}constructor(...args){super(...args),this.isWidget=true,this.characterCount=()=>{return this.props.userInput.currentValue.replace(/\n/g,"").length},this._handleUserInput=newValue=>{this.props.handleUserInput({currentValue:newValue});};}}FreeResponse.contextType=PerseusI18nContext;FreeResponse.defaultProps={userInput:{currentValue:""}};function getStartUserInput$c(){return {currentValue:""}}var FreeResponse$1 = {name:"free-response",accessible:true,displayName:"Free Response (Assessments only)",widget:FreeResponse,hidden:false,getUserInputFromSerializedState:getStartUserInput$c,getStartUserInput: getStartUserInput$c};const styles$k=aphrodite.StyleSheet.create({container:{gap:wonderBlocksTokens.spacing.xSmall_8},characterCountText:{color:wonderBlocksTokens.semanticColor.core.foreground.neutral.default,fontSize:wonderBlocksTokens.font.size.small},overCharacterLimit:{color:wonderBlocksTokens.color.red},textarea:{padding:wonderBlocksTokens.spacing.medium_16},warningCircleIcon:{marginInlineEnd:wonderBlocksTokens.spacing.xSmall_8}});
|
|
1855
1857
|
|
|
1856
1858
|
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 perseusCore.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}
|
|
1857
1859
|
|
|
@@ -1873,7 +1875,7 @@ const getPromptJSON$g=renderProps=>{const{userInput}=renderProps;const{type,coor
|
|
|
1873
1875
|
|
|
1874
1876
|
const movableTypeToComponent={PLOT:Graphie.Plot,PARABOLA:Graphie.Parabola,SINUSOID:Graphie.Sinusoid};const DEFAULT_BACKGROUND_IMAGE={url:null};const getEquationString=plot=>{if(plot.type&&plot.coords){const handler=perseusCore.GrapherUtil.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 kmath.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=perseusCore.GrapherUtil.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=___default.default.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(perseusCore.GrapherUtil.functionForType(type).url),alt:capitalized})}};
|
|
1875
1877
|
|
|
1876
|
-
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__namespace.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=this._coords().every((otherCoord,j)=>{return i===j||!otherCoord||!kmath.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=perseusCore.deepClone(this._coords());const oldCoord=perseusCore.deepClone(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=this._coords().map(coord=>{return kmath.point.reflectOverLine(coord,asymptote)});}else {coords=perseusCore.deepClone(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=this._coords().map(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.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 React.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=kmath.vector.subtract(newCoord,oldCoord);const newAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));this.props.onChange({asymptote:newAsymptote});},constraints:[Interactive2.MovableLine.constraints.bound(),Interactive2.MovableLine.constraints.snap(),(newCoord,oldCoord)=>{const delta=kmath.vector.subtract(newCoord,oldCoord);const proposedAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));if(model.extraAsymptoteConstraint){return model.extraAsymptoteConstraint(newCoord,oldCoord,this._coords(),proposedAsymptote,graph)}return true}],normalStyle:dashed,highlightStyle:dashed,children:asymptote.map((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__namespace.Component{_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}getPromptJSON(){return getPromptJSON$g(this.props)}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,plot:this.props.userInput}}render(){const type=this.props.userInput.type;const coords=this.props.userInput.coords;const asymptote="asymptote"in this.props.userInput?this.props.userInput.asymptote:undefined;const typeSelector=jsxRuntimeExports.jsx("div",{style:typeSelectorStyle,children:jsxRuntimeExports.jsx(ButtonGroup,{value:type,allowEmpty:true,buttons:
|
|
1878
|
+
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__namespace.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=this._coords().every((otherCoord,j)=>{return i===j||!otherCoord||!kmath.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=perseusCore.deepClone(this._coords());const oldCoord=perseusCore.deepClone(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=this._coords().map(coord=>{return kmath.point.reflectOverLine(coord,asymptote)});}else {coords=perseusCore.deepClone(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=this._coords().map(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.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 React.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=kmath.vector.subtract(newCoord,oldCoord);const newAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));this.props.onChange({asymptote:newAsymptote});},constraints:[Interactive2.MovableLine.constraints.bound(),Interactive2.MovableLine.constraints.snap(),(newCoord,oldCoord)=>{const delta=kmath.vector.subtract(newCoord,oldCoord);const proposedAsymptote=this._asymptote().map(coord=>kmath.vector.add(coord,delta));if(model.extraAsymptoteConstraint){return model.extraAsymptoteConstraint(newCoord,oldCoord,this._coords(),proposedAsymptote,graph)}return true}],normalStyle:dashed,highlightStyle:dashed,children:asymptote.map((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__namespace.Component{_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}getPromptJSON(){return getPromptJSON$g(this.props)}getSerializedState(){const{userInput:_,correct:__,...rest}=this.props;return {...rest,plot:this.props.userInput}}render(){const availableTypes=this.props.static?[this.props.correct.type]:this.props.availableTypes;const type=this.props.userInput.type;const coords=this.props.userInput.coords;const asymptote="asymptote"in this.props.userInput?this.props.userInput.asymptote:undefined;const typeSelector=jsxRuntimeExports.jsx("div",{style:typeSelectorStyle,children:jsxRuntimeExports.jsx(ButtonGroup,{value:type,allowEmpty:true,buttons:availableTypes.map(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&&perseusCore.GrapherUtil.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}),availableTypes.length>1&&typeSelector]})}constructor(...args){super(...args),this.handlePlotChanges=newPlot=>{const plot={...this.props.userInput,...newPlot};this.props.handleUserInput(plot);this.props.trackInteraction();},this.handleActiveTypeChange=newType=>{const graph=this.props.graph;const plot={...this.props.userInput,...defaultPlotProps(newType,graph)};this.props.handleUserInput(plot);},this._setupGraphie=(graphie,options)=>{const isMobile=this.props.apiOptions.isMobile;if(options.markings==="graph"){graphie.graphInit({range:options.range,scale:options.gridConfig.map(e=>e.scale),axisArrows:"<->",labelFormat:function(s){return "\\small{"+s+"}"},gridStep:options.gridStep,snapStep:options.snapStep,tickStep:isMobile?this._calculateMobileTickStep(options.gridStep,options.step,options.range):options.gridConfig.map(e=>e.tickStep),labelStep:1,unityLabels:options.gridConfig.map(e=>e.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:options.gridConfig.map(e=>e.scale),gridStep:options.gridStep,axes:false,ticks:false,labels:false,isMobile:isMobile});}else if(options.markings==="none"){graphie.init({range:options.range,scale:options.gridConfig.map(e=>e.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.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();}};}}function getUserInputFromSerializedState$b(serializedState){return serializedState.plot}function getStartUserInput$b(options){if(options.availableTypes.length===1){const graph=options.graph;const type=chooseType(options.availableTypes);if(type){return defaultPlotProps(type,graph)}}return DEFAULT_GRAPHER_PROPS.plot}function getCorrectUserInput$4(options){return options.correct}var Grapher$1 = {name:"grapher",displayName:"Grapher",hidden:true,widget:Grapher,getUserInputFromSerializedState: getUserInputFromSerializedState$b,getStartUserInput: getStartUserInput$b,getCorrectUserInput: getCorrectUserInput$4};
|
|
1877
1879
|
|
|
1878
1880
|
const getPromptJSON$f=rendererJSON=>{if(!rendererJSON){return {type:"group",content:"",widgets:{}}}return {...rendererJSON,type:"group"}};
|
|
1879
1881
|
|
|
@@ -1909,13 +1911,13 @@ function lerp(a,b,fraction){return (b-a)*clamp(fraction,0,1)+a}
|
|
|
1909
1911
|
|
|
1910
1912
|
const segmentsIntersect=([[a,b],[c,d]],[[p,q],[r,s]])=>{const determinant=(c-a)*(s-q)-(r-p)*(d-b);if(determinant===0){return false}else {const lambda=((s-q)*(r-a)+(p-r)*(s-b))/determinant;const gamma=((b-d)*(r-a)+(c-a)*(s-b))/determinant;return 0<lambda&&lambda<1&&0<gamma&&gamma<1}};function findIntersectionOfRays([[a,b],[c,d]],[[p,q],[r,s]]){const determinant=(c-a)*(s-q)-(r-p)*(d-b);if(determinant===0){return undefined}else {const lambda=((s-q)*(r-a)+(p-r)*(s-b))/determinant;const gamma=((b-d)*(r-a)+(c-a)*(s-b))/determinant;if(lambda<=0||gamma>=1){return undefined}const initialPoint=[a,b];const direction=mafs.vec.sub([c,d],initialPoint);return mafs.vec.add(initialPoint,mafs.vec.scale(direction,lambda))}}
|
|
1911
1913
|
|
|
1912
|
-
const defaultGraphConfig={range:[[0,1],[0,1]],tickStep:[1,1],gridStep:[1,1],snapStep:[1,1],markings:"none",showTooltips:false,graphDimensionsInPixels:[1,1],width:0,height:0,labels:[],labelLocation:"onAxis",disableKeyboardInteraction:false,interactiveColor:"var(--mafs-blue)"};const GraphConfigContext=React.createContext(defaultGraphConfig);function useGraphConfig(){return React__namespace.default.useContext(GraphConfigContext)}
|
|
1914
|
+
const defaultGraphConfig={range:[[0,1],[0,1]],tickStep:[1,1],gridStep:[1,1],snapStep:[1,1],markings:"none",showTooltips:false,graphDimensionsInPixels:[1,1],width:0,height:0,labels:[],labelLocation:"onAxis",disableKeyboardInteraction:false,interactiveColor:"var(--mafs-blue)",showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true}};const GraphConfigContext=React.createContext(defaultGraphConfig);function useGraphConfig(){return React__namespace.default.useContext(GraphConfigContext)}
|
|
1913
1915
|
|
|
1914
1916
|
const matrixBuilder=mafs.vec.matrixBuilder;function vectorsToPixels(vectors,graphState,translation=[0,0]){const{range,width,height}=graphState;const[[xMin,xMax],[yMin,yMax]]=range;const transformToPx=matrixBuilder().translate(...translation).scale(width/(xMax-xMin),-height/(yMax-yMin)).get();return vectors.map(p=>mafs.vec.transform(p,transformToPx))}function dimensionsToPixels(dimens,graphState){const{range,width,height}=graphState;const[[xMin,xMax],[yMin,yMax]]=range;const transformToPx=matrixBuilder().scale(width/(xMax-xMin),height/(yMax-yMin)).get();return dimens.map(d=>mafs.vec.transform(d,transformToPx))}function pointToPixel(point,graphState){const[[xMin],[,yMax]]=graphState.range;const[a,b]=[-xMin,-yMax];return vectorsToPixels([point],graphState,[a,b])[0]}const useTransformVectorsToPixels=(...vectors)=>{const graphState=useGraphConfig();return vectorsToPixels(vectors,graphState)};const useTransformDimensionsToPixels=(...dimens)=>{const graphState=useGraphConfig();return dimensionsToPixels(dimens,graphState)};function pixelsToVectors(pixels,graphState){const[[xMin,xMax],[yMin,yMax]]=graphState.range;const{width,height}=graphState;const xSpan=xMax-xMin;const ySpan=yMax-yMin;return pixels.map(pixel=>{const x=pixel[X]/width*xSpan+xMin;const y=yMax-pixel[Y]/height*ySpan;return [x,y]})}
|
|
1915
1917
|
|
|
1916
1918
|
const arrowPath=pathBuilder().move(-3,4).curve(-2.75,2.5,0,.25,.75,0).curve(0,-0.25,-2.75,-2.5,-3,-4).scale(1.4).build();function Arrowhead(props){const[point]=useTransformVectorsToPixels(props.tip);return jsxRuntimeExports.jsx("g",{"aria-hidden":true,className:"interactive-graph-arrowhead",transform:`translate(${point[X]} ${point[Y]}) rotate(${props.angle})`,children:jsxRuntimeExports.jsx("g",{transform:"translate(-1.5)",children:jsxRuntimeExports.jsx("path",{d:arrowPath,fill:"none",style:{stroke:props.color??"inherit"},strokeLinejoin:"round",strokeLinecap:"round",strokeWidth:`${props.strokeWidth??2}px`})})})}
|
|
1917
1919
|
|
|
1918
|
-
function AxisArrows(){const{range:[[xMin,xMax],[yMin,yMax]]}=useGraphConfig();const axisColor="var(--mafs-fg)";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[!(yMin>0||yMax<0)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[xMin,0],angle:180}),jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[xMax,0],angle:0})]}),!(xMin>0||xMax<0)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[0,yMin],angle:90}),jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[0,yMax],angle:270})]})]})}
|
|
1920
|
+
function AxisArrows(){const{range:[[xMin,xMax],[yMin,yMax]],showAxisArrows}=useGraphConfig();const axisColor="var(--mafs-fg)";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[!(yMin>0||yMax<0)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[showAxisArrows.xMin&&jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[xMin,0],angle:180}),showAxisArrows.xMax&&jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[xMax,0],angle:0})]}),!(xMin>0||xMax<0)&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[showAxisArrows.yMin&&jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[0,yMin],angle:90}),showAxisArrows.yMax&&jsxRuntimeExports.jsx(Arrowhead,{color:axisColor,tip:[0,yMax],angle:270})]})]})}
|
|
1919
1921
|
|
|
1920
1922
|
const TARGET_SIZE=44;const REMOVE_BUTTON_ID="perseus_mafs_remove_button";const normalizePoints=(range,step,coordsList,noSnap)=>coordsList.map(coords=>coords.map((coord,i)=>{const axisRange=range[i];if(noSnap){return axisRange[MIN]+size(axisRange)*coord}const axisStep=step[i];const nSteps=Math.floor(size(axisRange)/axisStep);const tick=Math.round(coord*nSteps);return axisRange[MIN]+axisStep*tick}));const normalizeCoords=(coordsList,ranges)=>coordsList.map(coords=>coords.map((coord,i)=>{return (coord+ranges[i][1])/size(ranges[i])}));function bound$1({snapStep,range,point}){const boundingBox=inset(snapStep,range);return clampToBox(boundingBox,point)}function boundToEdge({range,point}){return clampToBox(range,point)}function isUnlimitedGraphState(state){return state.type==="point"&&state.numPoints==="unlimited"||state.type==="polygon"&&state.numSides==="unlimited"}const mathOnlyParser=SimpleMarkdown__default.default.parserFor({math:{...pureMarkdown.pureMarkdownRules.math,order:0},text:{order:1,match:SimpleMarkdown__default.default.anyScopeRegex(/^([^$\\{}]+)/),parse:capture=>({content:capture[0]})},specialCharacter:{order:2,match:SimpleMarkdown__default.default.anyScopeRegex(/^(\\[\S\s]|\$|\\$|{|})/),parse:capture=>({content:capture[0]})}},{inline:true});function replaceOutsideTeX(mathString){const parsed=mathOnlyParser(mathString);let result="";for(const piece of parsed){piece.type==="math"?result+="$"+piece.content+"$":piece.type==="specialCharacter"?result+=escapeIfUnescaped(piece.content):result+=piece.content;}return `\\text{${result}}`}function escapeIfUnescaped(character){if(character.length===1){return "\\"+character}else {return character}}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}};
|
|
1921
1923
|
|
|
@@ -2040,13 +2042,13 @@ function renderSinusoidGraph(state,dispatch,i18n){return {graph:jsxRuntimeExport
|
|
|
2040
2042
|
|
|
2041
2043
|
const{calculateAngleInDegrees,convertDegreesToRadians}=kmath.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]=React.useState(initialCenter);const[rotationHandleOffset,setRotationHandleOffset]=React.useState(centerToRotationHandle);const draggableRef=React.useRef(null);const{dragging}=useDraggable({gestureTarget:draggableRef,onMove:setCenter,point:center,constrainKeyboardMovement:point=>bound$1({snapStep,range,point})});const rotationHandleRef=React.useRef(null);useDraggablePx({gestureTarget:rotationHandleRef,onMove:setRotationHandleOffset,point:rotationHandleOffset,constrain:constrainToCircle});const[centerPx]=useTransformVectorsToPixels(center);const topLeftPx=mafs.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=mafs.vec.mag(centerToRotationHandle);function constrainToCircle(edgePoint){return mafs.vec.withMag(edgePoint,protractorRadius)}function useDraggablePx(args){const{gestureTarget:target,onMove,point,constrain=p=>p}=args;const pickupPx=React__namespace.useRef([0,0]);react.useDrag(state=>{const{event,first,movement:pixelMovement}=state;event?.stopPropagation();if(first){pickupPx.current=point;}if(mafs.vec.mag(pixelMovement)===0){return}onMove?.(constrain(mafs.vec.add(pickupPx.current,pixelMovement)));},{target,eventOptions:{passive:false}});}
|
|
2042
2044
|
|
|
2043
|
-
const GRAPH_LEFT_MARGIN=20;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__namespace.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__namespace.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;wonderBlocksCore.useOnMountEffect(()=>{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;const graphInfo={range:state.range,width,height};const[xAxisLabelLocation,yAxisLabelLocation]=getLabelPosition(graphInfo,labelLocation,tickStep);const needsExtraMargin=labelLocation==="alongEdge"&&yAxisLabelLocation[0]<-14*fontSizeYAxisLabelMultiplier;const marginLabelDiff=GRAPH_LEFT_MARGIN-fontSize*fontSizeYAxisLabelMultiplier;const marginWithExtraOffset=-1*(yAxisLabelLocation[X]-marginLabelDiff);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(wonderBlocksCore.View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:"mafs-graph",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:needsExtraMargin?`${marginWithExtraOffset}px`:`${GRAPH_LEFT_MARGIN}px`,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(wonderBlocksCore.View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),state.type!=="none"&&jsxRuntimeExports.jsx(wonderBlocksCore.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(wonderBlocksCore.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,xAxisLabelLocation:xAxisLabelLocation,yAxisLabelLocation:yAxisLabelLocation})}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{"aria-hidden":props.lockedFigures.length===0,children:jsxRuntimeExports.jsxs(mafs.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(wonderBlocksCore.View,{style:{position:"absolute"},children:jsxRuntimeExports.jsx(mafs.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,style:{overflow:type==="point"?"visible":"hidden"},children:[props.showProtractor&&jsxRuntimeExports.jsx(Protractor,{}),graph]})})})]}),interactionPrompt&&jsxRuntimeExports.jsx(wonderBlocksCore.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(wonderBlocksTypography.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(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{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__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"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__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button__default.default,{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(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{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__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"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 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 wonderStuffCore.UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
|
|
2045
|
+
const GRAPH_LEFT_MARGIN=20;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__namespace.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__namespace.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;wonderBlocksCore.useOnMountEffect(()=>{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;const graphInfo={range:state.range,width,height};const[xAxisLabelLocation,yAxisLabelLocation]=getLabelPosition(graphInfo,labelLocation,tickStep);const needsExtraMargin=labelLocation==="alongEdge"&&yAxisLabelLocation[0]<-14*fontSizeYAxisLabelMultiplier;const marginLabelDiff=GRAPH_LEFT_MARGIN-fontSize*fontSizeYAxisLabelMultiplier;const marginWithExtraOffset=-1*(yAxisLabelLocation[X]-marginLabelDiff);return jsxRuntimeExports.jsx(GraphConfigContext.Provider,{value:{range:state.range,snapStep:state.snapStep,markings:props.markings,tickStep:tickStep,gridStep:props.gridStep,showTooltips:!!props.showTooltips,showAxisArrows:props.showAxisArrows,graphDimensionsInPixels:props.box,width,height,labels,labelLocation,disableKeyboardInteraction:disableInteraction,interactiveColor:disableInteraction?"var(--static-gray)":"var(--mafs-blue)"},children:jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:"mafs-graph-container",children:[jsxRuntimeExports.jsxs(wonderBlocksCore.View,{className:"mafs-graph",style:{position:"relative",padding:"25px 25px 0 0",boxSizing:"content-box",marginLeft:needsExtraMargin?`${marginWithExtraOffset}px`:`${GRAPH_LEFT_MARGIN}px`,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(wonderBlocksCore.View,{id:descriptionId,tabIndex:-1,className:"mafs-sr-only",children:fullGraphAriaDescription}),interactiveElementsDescription&&jsxRuntimeExports.jsx(wonderBlocksCore.View,{id:interactiveElementsDescriptionId,tabIndex:-1,className:"mafs-sr-only",children:interactiveElementsDescription}),state.type!=="none"&&jsxRuntimeExports.jsx(wonderBlocksCore.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(wonderBlocksCore.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,xAxisLabelLocation:xAxisLabelLocation,yAxisLabelLocation:yAxisLabelLocation})}),jsxRuntimeExports.jsx(wonderBlocksCore.View,{"aria-hidden":props.lockedFigures.length===0,children:jsxRuntimeExports.jsxs(mafs.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(wonderBlocksCore.View,{style:{position:"absolute"},children:jsxRuntimeExports.jsx(mafs.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,style:{overflow:type==="point"?"visible":"hidden"},children:[props.showProtractor&&jsxRuntimeExports.jsx(Protractor,{}),graph]})})})]}),interactionPrompt&&jsxRuntimeExports.jsx(wonderBlocksCore.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(wonderBlocksTypography.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(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{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__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"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__default.default,{kind:"secondary",style:{width:"100%",marginLeft:"20px"},tabIndex:0,onClick:()=>{props.dispatch(actions.polygon.openPolygon());},children:perseusStrings.openPolygon}):jsxRuntimeExports.jsx(Button__default.default,{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(wonderBlocksCore.View,{style:{flexDirection:"row",width:props.width},children:[interactionMode==="keyboard"&&jsxRuntimeExports.jsx(Button__default.default,{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__default.default,{id:REMOVE_BUTTON_ID,kind:"secondary",actionType:"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 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 wonderStuffCore.UnreachableCaseError(type)}};function describedByIds(...args){return args.filter(Boolean).join(" ")||undefined}
|
|
2044
2046
|
|
|
2045
2047
|
function mafsStateToInteractiveGraph(state,originalGraph){switch(state.type){case "angle":invariant__default.default(originalGraph.type==="angle");return {...originalGraph,coords:state.coords};case "quadratic":invariant__default.default(originalGraph.type==="quadratic");return {...originalGraph,coords:state.coords};case "circle":invariant__default.default(originalGraph.type==="circle");return {...originalGraph,center:state.center,radius:getRadius(state)};case "linear":invariant__default.default(originalGraph.type==="linear");return {...originalGraph,coords:state.coords};case "ray":invariant__default.default(originalGraph.type==="ray");return {...originalGraph,coords:state.coords};case "sinusoid":invariant__default.default(originalGraph.type==="sinusoid");return {...originalGraph,coords:state.coords};case "segment":invariant__default.default(originalGraph.type==="segment");return {...originalGraph,coords:state.coords};case "linear-system":invariant__default.default(originalGraph.type==="linear-system");return {...originalGraph,coords:state.coords};case "polygon":invariant__default.default(originalGraph.type==="polygon");return {...originalGraph,coords:state.coords};case "point":invariant__default.default(originalGraph.type==="point");return {...originalGraph,coords:state.coords};case "none":invariant__default.default(originalGraph.type==="none");return {...originalGraph};default:throw new wonderStuffCore.UnreachableCaseError(state)}}
|
|
2046
2048
|
|
|
2047
2049
|
const StatefulMafsGraph=React__namespace.forwardRef(function StatefulMafsGraphWithRef(props,ref){const{onChange,graph}=props;const[state,dispatch]=React__namespace.useReducer(interactiveGraphReducer,props,initializeGraphState);React.useImperativeHandle(ref,()=>({getUserInput:()=>getGradableGraph(state,graph)}));const prevState=React.useRef(state);React.useEffect(()=>{if(prevState.current!==state){onChange(mafsStateToInteractiveGraph(state,graph));}prevState.current=state;},[onChange,state,graph]);const[xSnap,ySnap]=props.snapStep;React.useEffect(()=>{dispatch(changeSnapStep([xSnap,ySnap]));},[dispatch,xSnap,ySnap]);const[[xMinRange,xMaxRange],[yMinRange,yMaxRange]]=props.range;React.useEffect(()=>{dispatch(changeRange([[xMinRange,xMaxRange],[yMinRange,yMaxRange]]));},[dispatch,xMinRange,xMaxRange,yMinRange,yMaxRange]);const numSegments=graph.type==="segment"?graph.numSegments:null;const numPoints=graph.type==="point"?graph.numPoints:null;const numSides=graph.type==="polygon"?graph.numSides:null;const snapTo=graph.type==="polygon"?graph.snapTo:null;const showAngles=graph.type==="polygon"||graph.type==="angle"?graph.showAngles:null;const allowReflexAngles=graph.type==="angle"?graph.allowReflexAngles:null;const showSides=graph.type==="polygon"?graph.showSides:null;const startCoords="startCoords"in graph?graph.startCoords:undefined;const originalPropsRef=React.useRef(props);const latestPropsRef=wonderBlocksCore.useLatestRef(props);React.useEffect(()=>{if(latestPropsRef.current!==originalPropsRef.current){dispatch(reinitialize(latestPropsRef.current));}},[graph.type,numPoints,numSegments,numSides,snapTo,showAngles,showSides,latestPropsRef,startCoords,allowReflexAngles]);if(props.static&&props.correct){return jsxRuntimeExports.jsx(MafsGraph,{...props,state:initializeGraphState({...props,graph:props.correct}),dispatch:dispatch})}return jsxRuntimeExports.jsx(MafsGraph,{...props,state:state,dispatch:dispatch})});
|
|
2048
2050
|
|
|
2049
|
-
const{getClockwiseAngle}=kmath.angles;const{getLineEquation,getLineIntersectionString,magnitude,vector}=kmath.geometry;const defaultBackgroundImage={url:null};const UNLIMITED="unlimited";function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}const makeInvalidTypeError=(functionName,graphType)=>{return new perseusCore.PerseusError(`${functionName} called but current graph type is not a '${graphType}'`,perseusCore.Errors.NotAllowed,{metadata:{graphType}})};function getSinusoidCoefficients(coords){const p1=coords[0];const p2=coords[1];const amplitude=p2[1]-p1[1];const angularFrequency=Math.PI/(2*(p2[0]-p1[0]));const phase=p1[0]*angularFrequency;const verticalOffset=p1[1];return [amplitude,angularFrequency,phase,verticalOffset]}function getQuadraticCoefficients(coords){const p1=coords[0];const p2=coords[1];const p3=coords[2];const denom=(p1[0]-p2[0])*(p1[0]-p3[0])*(p2[0]-p3[0]);if(denom===0){return}const a=(p3[0]*(p2[1]-p1[1])+p2[0]*(p1[1]-p3[1])+p1[0]*(p3[1]-p2[1]))/denom;const b=(p3[0]*p3[0]*(p1[1]-p2[1])+p2[0]*p2[0]*(p3[1]-p1[1])+p1[0]*p1[0]*(p2[1]-p3[1]))/denom;const c=(p2[0]*p3[0]*(p2[0]-p3[0])*p1[1]+p3[0]*p1[0]*(p3[0]-p1[0])*p2[1]+p1[0]*p2[0]*(p1[0]-p2[0])*p3[1])/denom;return [a,b,c]}class InteractiveGraph extends React__namespace.Component{getUserInput(){if(this.mafsRef.current?.getUserInput){return this.mafsRef.current.getUserInput()}throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered",perseusCore.Errors.NotAllowed)}getPromptJSON(){return getPromptJSON$b(this.props,this.getUserInput())}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,graph:this.props.userInput}}render(){const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,box[0]);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const mafsProps={...this.props,graph:this.props.userInput,onChange:()=>this.props.handleUserInput(this.mafsRef.current?.getUserInput())};return jsxRuntimeExports.jsx(StatefulMafsGraph,{...mafsProps,ref:this.mafsRef,gridStep:gridStep,snapStep:snapStep,box:box,showTooltips:!!this.props.showTooltips,readOnly:this.props.apiOptions?.readOnly})}static getLineCoords(graph,props){return graph.coords||InteractiveGraph.pointsFromNormalized(props,[[.25,.75],[.75,.75]])}static getPointCoords(graph,props){const numPoints=graph.numPoints||1;let coords=graph.coords;if(coords){return coords}switch(numPoints){case 1:coords=[graph.coord||[0,0]];break;case 2:coords=[[-5,0],[5,0]];break;case 3:coords=[[-5,0],[0,0],[5,0]];break;case 4:coords=[[-6,0],[-2,0],[2,0],[6,0]];break;case 5:coords=[[-6,0],[-3,0],[0,0],[3,0],[6,0]];break;case 6:coords=[[-5,0],[-3,0],[-1,0],[1,0],[3,0],[5,0]];break;case UNLIMITED:coords=[];break}const range=[[-10,10],[-10,10]];const newCoords=InteractiveGraph.normalizeCoords(coords,range);return InteractiveGraph.pointsFromNormalized(props,newCoords)}static getLinearSystemCoords(graph,props){return graph.coords||___default.default.map([[[.25,.75],[.75,.75]],[[.25,.25],[.75,.25]]],coords=>{return InteractiveGraph.pointsFromNormalized(props,coords)})}static getPolygonCoords(graph,props){if(graph.type!=="polygon"){throw makeInvalidTypeError("toggleShowSides","polygon")}let coords=graph.coords;if(coords){return coords}const n=graph.numSides||3;if(n===UNLIMITED){coords=[];}else {const angle=2*Math.PI/n;const offset=(1/n-1/2)*Math.PI;const radius=graph.snapTo==="sides"?Math.sqrt(3)/3*7:4;coords=___default.default.times(n,function(i){return [radius*Math.cos(i*angle+offset),radius*Math.sin(i*angle+offset)]});}const ranges=[[-10,10],[-10,10]];coords=InteractiveGraph.normalizeCoords(coords,ranges);const snapToGrid=!___default.default.contains(["angles","sides"],graph.snapTo);coords=InteractiveGraph.pointsFromNormalized(props,coords,!snapToGrid);return coords}static getSegmentCoords(graph,props){const coords=graph.coords;if(coords){return coords}const n=graph.numSegments||1;const ys={1:[5],2:[5,-5],3:[5,0,-5],4:[6,2,-2,-6],5:[6,3,0,-3,-6],6:[5,3,1,-1,-3,-5]}[n];const range=[[-10,10],[-10,10]];return ys.map(function(y){let segment=[[-5,y],[5,y]];segment=InteractiveGraph.normalizeCoords(segment,range);segment=InteractiveGraph.pointsFromNormalized(props,segment);return segment})}static getAngleCoords(graph,props){let coords=graph.coords;if(coords){return coords}const snap=graph.snapDegrees||1;let angle=snap;while(angle<20){angle+=snap;}angle=angle*Math.PI/180;const offset=(graph.angleOffsetDeg||0)*Math.PI/180;coords=InteractiveGraph.pointsFromNormalized(props,[[.85,.5],[.5,.5]]);const radius=magnitude(vector(...coords));coords[0]=[coords[1][0]+radius*Math.cos(offset),coords[1][1]+radius*Math.sin(offset)];coords[2]=[coords[1][0]+radius*Math.cos(angle+offset),coords[1][1]+radius*Math.sin(angle+offset)];return coords}static normalizeCoords(coordsList,ranges){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const extent=ranges[i][1]-ranges[i][0];return (coord+ranges[i][1])/extent})})}static getEquationString(props){const type=props.userInput.type;switch(type){case "none":return InteractiveGraph.getNoneEquationString();case "linear":return InteractiveGraph.getLinearEquationString(props);case "quadratic":return InteractiveGraph.getQuadraticEquationString(props);case "sinusoid":return InteractiveGraph.getSinusoidEquationString(props);case "circle":return InteractiveGraph.getCircleEquationString(props);case "linear-system":return InteractiveGraph.getLinearSystemEquationString(props);case "point":return InteractiveGraph.getPointEquationString(props);case "segment":return InteractiveGraph.getSegmentEquationString(props);case "ray":return InteractiveGraph.getRayEquationString(props);case "polygon":return InteractiveGraph.getPolygonEquationString(props);case "angle":return InteractiveGraph.getAngleEquationString(props);default:throw new wonderStuffCore.UnreachableCaseError(type)}}static pointsFromNormalized(props,coordsList,noSnap){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const range=props.range[i];if(noSnap){return range[0]+(range[1]-range[0])*coord}const step=props.step[i];const nSteps=numSteps(range,step);const tick=Math.round(coord*nSteps);return range[0]+step*tick})})}static getNoneEquationString(){return ""}static getLinearEquationString(props){const coords=InteractiveGraph.getLineCoords(props.userInput,props);if(perseusCore.approximateEqual(coords[0][0],coords[1][0])){return "x = "+coords[0][0].toFixed(3)}const m=(coords[1][1]-coords[0][1])/(coords[1][0]-coords[0][0]);const b=coords[0][1]-m*coords[0][0];if(perseusCore.approximateEqual(m,0)){return "y = "+b.toFixed(3)}return "y = "+m.toFixed(3)+"x + "+b.toFixed(3)}static getCurrentQuadraticCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultQuadraticCoords(props);return getQuadraticCoefficients(coords)}static defaultQuadraticCoords(props){const coords=[[.25,.75],[.5,.25],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getQuadraticEquationString(props){const coeffs=InteractiveGraph.getCurrentQuadraticCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"x^2 + "+coeffs[1].toFixed(3)+"x + "+coeffs[2].toFixed(3)}static getCurrentSinusoidCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultSinusoidCoords(props);return getSinusoidCoefficients(coords)}static defaultSinusoidCoords(props){const coords=[[.5,.5],[.65,.6]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getSinusoidEquationString(props){const coeffs=InteractiveGraph.getCurrentSinusoidCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"sin("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}static getCircleEquationString(props){const graph=props.userInput;const center=graph.center||[0,0];const radius=graph.radius||2;return "center ("+center[0]+", "+center[1]+"), radius "+radius}static getLinearSystemEquationString(props){const coords=InteractiveGraph.getLinearSystemCoords(props.userInput,props);return "\n"+getLineEquation(coords[0][0],coords[0][1])+"\n"+getLineEquation(coords[1][0],coords[1][1])+"\n"+getLineIntersectionString(coords[0],coords[1])}static getPointEquationString(props){if(props.userInput.type!=="point"){throw makeInvalidTypeError("getPointEquationString","point")}const coords=InteractiveGraph.getPointCoords(props.userInput,props);return coords.map(function(coord){return "("+coord[0]+", "+coord[1]+")"}).join(", ")}static getSegmentEquationString(props){if(props.userInput.type!=="segment"){throw makeInvalidTypeError("getSegmentEquationString","segment")}const segments=InteractiveGraph.getSegmentCoords(props.userInput,props);return ___default.default.map(segments,function(segment){return "["+___default.default.map(segment,function(coord){return "("+coord.join(", ")+")"}).join(" ")+"]"}).join(" ")}static getRayEquationString(props){if(props.userInput.type!=="ray"){throw makeInvalidTypeError("createPointForPolygonType","ray")}const coords=InteractiveGraph.getLineCoords(props.userInput,props);const a=coords[0];const b=coords[1];let eq=InteractiveGraph.getLinearEquationString(props);if(a[0]>b[0]){eq+=" (for x <= "+a[0].toFixed(3)+")";}else if(a[0]<b[0]){eq+=" (for x >= "+a[0].toFixed(3)+")";}else if(a[1]>b[1]){eq+=" (for y <= "+a[1].toFixed(3)+")";}else {eq+=" (for y >= "+a[1].toFixed(3)+")";}return eq}static getPolygonEquationString(props){if(props.userInput.type!=="polygon"){throw makeInvalidTypeError("getPolygonEquationString","polygon")}const coords=InteractiveGraph.getPolygonCoords(props.userInput,props);return ___default.default.map(coords,function(coord){return "("+coord.join(", ")+")"}).join(" ")}static getAngleEquationString(props){if(props.userInput.type!=="angle"){throw makeInvalidTypeError("getAngleEquationString","angle")}const coords=InteractiveGraph.getAngleCoords(props.userInput,props);const allowReflexAngles=props.userInput.allowReflexAngles;const angle=getClockwiseAngle(coords,allowReflexAngles);return angle.toFixed(0)+"° angle"+" at ("+coords[1].join(", ")+")"}constructor(...args){super(...args),this.mafsRef=React__namespace.createRef();}}InteractiveGraph.defaultProps={labels:["x","y"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],step:[1,1],backgroundImage:defaultBackgroundImage,markings:"graph",showTooltips:false,showProtractor:false,userInput:{type:"linear"}};function getUserInputFromSerializedState$8(serializedState){return serializedState.graph}function getStartUserInput$8(options){return options.graph}function getCorrectUserInput$3(options){return options.correct}var InteractiveGraph$1 = {name:"interactive-graph",displayName:"Interactive graph",widget:InteractiveGraph,staticTransform:___default.default.identity,getStartUserInput: getStartUserInput$8,getCorrectUserInput: getCorrectUserInput$3,getUserInputFromSerializedState: getUserInputFromSerializedState$8};
|
|
2051
|
+
const{getClockwiseAngle}=kmath.angles;const{getLineEquation,getLineIntersectionString,magnitude,vector}=kmath.geometry;const defaultBackgroundImage={url:null};const UNLIMITED="unlimited";function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}const makeInvalidTypeError=(functionName,graphType)=>{return new perseusCore.PerseusError(`${functionName} called but current graph type is not a '${graphType}'`,perseusCore.Errors.NotAllowed,{metadata:{graphType}})};function getSinusoidCoefficients(coords){const p1=coords[0];const p2=coords[1];const amplitude=p2[1]-p1[1];const angularFrequency=Math.PI/(2*(p2[0]-p1[0]));const phase=p1[0]*angularFrequency;const verticalOffset=p1[1];return [amplitude,angularFrequency,phase,verticalOffset]}function getQuadraticCoefficients(coords){const p1=coords[0];const p2=coords[1];const p3=coords[2];const denom=(p1[0]-p2[0])*(p1[0]-p3[0])*(p2[0]-p3[0]);if(denom===0){return}const a=(p3[0]*(p2[1]-p1[1])+p2[0]*(p1[1]-p3[1])+p1[0]*(p3[1]-p2[1]))/denom;const b=(p3[0]*p3[0]*(p1[1]-p2[1])+p2[0]*p2[0]*(p3[1]-p1[1])+p1[0]*p1[0]*(p2[1]-p3[1]))/denom;const c=(p2[0]*p3[0]*(p2[0]-p3[0])*p1[1]+p3[0]*p1[0]*(p3[0]-p1[0])*p2[1]+p1[0]*p2[0]*(p1[0]-p2[0])*p3[1])/denom;return [a,b,c]}class InteractiveGraph extends React__namespace.Component{getUserInput(){if(this.mafsRef.current?.getUserInput){return this.mafsRef.current.getUserInput()}throw new perseusCore.PerseusError("Cannot getUserInput from a graph that has never rendered",perseusCore.Errors.NotAllowed)}getPromptJSON(){return getPromptJSON$b(this.props,this.getUserInput())}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,graph:this.props.userInput}}render(){const box=getInteractiveBoxFromSizeClass(this.props.containerSizeClass);const gridStep=this.props.gridStep||Util.getGridStep(this.props.range,this.props.step,box[0]);const snapStep=this.props.snapStep||Util.snapStepFromGridStep(gridStep);const mafsProps={...this.props,graph:this.props.userInput,onChange:()=>this.props.handleUserInput(this.mafsRef.current?.getUserInput())};return jsxRuntimeExports.jsx(StatefulMafsGraph,{...mafsProps,ref:this.mafsRef,gridStep:gridStep,snapStep:snapStep,box:box,showTooltips:!!this.props.showTooltips,readOnly:this.props.apiOptions?.readOnly})}static getLineCoords(graph,props){return graph.coords||InteractiveGraph.pointsFromNormalized(props,[[.25,.75],[.75,.75]])}static getPointCoords(graph,props){const numPoints=graph.numPoints||1;let coords=graph.coords;if(coords){return coords}switch(numPoints){case 1:coords=[graph.coord||[0,0]];break;case 2:coords=[[-5,0],[5,0]];break;case 3:coords=[[-5,0],[0,0],[5,0]];break;case 4:coords=[[-6,0],[-2,0],[2,0],[6,0]];break;case 5:coords=[[-6,0],[-3,0],[0,0],[3,0],[6,0]];break;case 6:coords=[[-5,0],[-3,0],[-1,0],[1,0],[3,0],[5,0]];break;case UNLIMITED:coords=[];break}const range=[[-10,10],[-10,10]];const newCoords=InteractiveGraph.normalizeCoords(coords,range);return InteractiveGraph.pointsFromNormalized(props,newCoords)}static getLinearSystemCoords(graph,props){return graph.coords||___default.default.map([[[.25,.75],[.75,.75]],[[.25,.25],[.75,.25]]],coords=>{return InteractiveGraph.pointsFromNormalized(props,coords)})}static getPolygonCoords(graph,props){if(graph.type!=="polygon"){throw makeInvalidTypeError("toggleShowSides","polygon")}let coords=graph.coords;if(coords){return coords}const n=graph.numSides||3;if(n===UNLIMITED){coords=[];}else {const angle=2*Math.PI/n;const offset=(1/n-1/2)*Math.PI;const radius=graph.snapTo==="sides"?Math.sqrt(3)/3*7:4;coords=___default.default.times(n,function(i){return [radius*Math.cos(i*angle+offset),radius*Math.sin(i*angle+offset)]});}const ranges=[[-10,10],[-10,10]];coords=InteractiveGraph.normalizeCoords(coords,ranges);const snapToGrid=!___default.default.contains(["angles","sides"],graph.snapTo);coords=InteractiveGraph.pointsFromNormalized(props,coords,!snapToGrid);return coords}static getSegmentCoords(graph,props){const coords=graph.coords;if(coords){return coords}const n=graph.numSegments||1;const ys={1:[5],2:[5,-5],3:[5,0,-5],4:[6,2,-2,-6],5:[6,3,0,-3,-6],6:[5,3,1,-1,-3,-5]}[n];const range=[[-10,10],[-10,10]];return ys.map(function(y){let segment=[[-5,y],[5,y]];segment=InteractiveGraph.normalizeCoords(segment,range);segment=InteractiveGraph.pointsFromNormalized(props,segment);return segment})}static getAngleCoords(graph,props){let coords=graph.coords;if(coords){return coords}const snap=graph.snapDegrees||1;let angle=snap;while(angle<20){angle+=snap;}angle=angle*Math.PI/180;const offset=(graph.angleOffsetDeg||0)*Math.PI/180;coords=InteractiveGraph.pointsFromNormalized(props,[[.85,.5],[.5,.5]]);const radius=magnitude(vector(...coords));coords[0]=[coords[1][0]+radius*Math.cos(offset),coords[1][1]+radius*Math.sin(offset)];coords[2]=[coords[1][0]+radius*Math.cos(angle+offset),coords[1][1]+radius*Math.sin(angle+offset)];return coords}static normalizeCoords(coordsList,ranges){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const extent=ranges[i][1]-ranges[i][0];return (coord+ranges[i][1])/extent})})}static getEquationString(props){const type=props.userInput.type;switch(type){case "none":return InteractiveGraph.getNoneEquationString();case "linear":return InteractiveGraph.getLinearEquationString(props);case "quadratic":return InteractiveGraph.getQuadraticEquationString(props);case "sinusoid":return InteractiveGraph.getSinusoidEquationString(props);case "circle":return InteractiveGraph.getCircleEquationString(props);case "linear-system":return InteractiveGraph.getLinearSystemEquationString(props);case "point":return InteractiveGraph.getPointEquationString(props);case "segment":return InteractiveGraph.getSegmentEquationString(props);case "ray":return InteractiveGraph.getRayEquationString(props);case "polygon":return InteractiveGraph.getPolygonEquationString(props);case "angle":return InteractiveGraph.getAngleEquationString(props);default:throw new wonderStuffCore.UnreachableCaseError(type)}}static pointsFromNormalized(props,coordsList,noSnap){return ___default.default.map(coordsList,function(coords){return ___default.default.map(coords,function(coord,i){const range=props.range[i];if(noSnap){return range[0]+(range[1]-range[0])*coord}const step=props.step[i];const nSteps=numSteps(range,step);const tick=Math.round(coord*nSteps);return range[0]+step*tick})})}static getNoneEquationString(){return ""}static getLinearEquationString(props){const coords=InteractiveGraph.getLineCoords(props.userInput,props);if(perseusCore.approximateEqual(coords[0][0],coords[1][0])){return "x = "+coords[0][0].toFixed(3)}const m=(coords[1][1]-coords[0][1])/(coords[1][0]-coords[0][0]);const b=coords[0][1]-m*coords[0][0];if(perseusCore.approximateEqual(m,0)){return "y = "+b.toFixed(3)}return "y = "+m.toFixed(3)+"x + "+b.toFixed(3)}static getCurrentQuadraticCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultQuadraticCoords(props);return getQuadraticCoefficients(coords)}static defaultQuadraticCoords(props){const coords=[[.25,.75],[.5,.25],[.75,.75]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getQuadraticEquationString(props){const coeffs=InteractiveGraph.getCurrentQuadraticCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"x^2 + "+coeffs[1].toFixed(3)+"x + "+coeffs[2].toFixed(3)}static getCurrentSinusoidCoefficients(props){const coords=props.userInput.coords||InteractiveGraph.defaultSinusoidCoords(props);return getSinusoidCoefficients(coords)}static defaultSinusoidCoords(props){const coords=[[.5,.5],[.65,.6]];return InteractiveGraph.pointsFromNormalized(props,coords)}static getSinusoidEquationString(props){const coeffs=InteractiveGraph.getCurrentSinusoidCoefficients(props);return "y = "+coeffs[0].toFixed(3)+"sin("+coeffs[1].toFixed(3)+"x - "+coeffs[2].toFixed(3)+") + "+coeffs[3].toFixed(3)}static getCircleEquationString(props){const graph=props.userInput;const center=graph.center||[0,0];const radius=graph.radius||2;return "center ("+center[0]+", "+center[1]+"), radius "+radius}static getLinearSystemEquationString(props){const coords=InteractiveGraph.getLinearSystemCoords(props.userInput,props);return "\n"+getLineEquation(coords[0][0],coords[0][1])+"\n"+getLineEquation(coords[1][0],coords[1][1])+"\n"+getLineIntersectionString(coords[0],coords[1])}static getPointEquationString(props){if(props.userInput.type!=="point"){throw makeInvalidTypeError("getPointEquationString","point")}const coords=InteractiveGraph.getPointCoords(props.userInput,props);return coords.map(function(coord){return "("+coord[0]+", "+coord[1]+")"}).join(", ")}static getSegmentEquationString(props){if(props.userInput.type!=="segment"){throw makeInvalidTypeError("getSegmentEquationString","segment")}const segments=InteractiveGraph.getSegmentCoords(props.userInput,props);return ___default.default.map(segments,function(segment){return "["+___default.default.map(segment,function(coord){return "("+coord.join(", ")+")"}).join(" ")+"]"}).join(" ")}static getRayEquationString(props){if(props.userInput.type!=="ray"){throw makeInvalidTypeError("createPointForPolygonType","ray")}const coords=InteractiveGraph.getLineCoords(props.userInput,props);const a=coords[0];const b=coords[1];let eq=InteractiveGraph.getLinearEquationString(props);if(a[0]>b[0]){eq+=" (for x <= "+a[0].toFixed(3)+")";}else if(a[0]<b[0]){eq+=" (for x >= "+a[0].toFixed(3)+")";}else if(a[1]>b[1]){eq+=" (for y <= "+a[1].toFixed(3)+")";}else {eq+=" (for y >= "+a[1].toFixed(3)+")";}return eq}static getPolygonEquationString(props){if(props.userInput.type!=="polygon"){throw makeInvalidTypeError("getPolygonEquationString","polygon")}const coords=InteractiveGraph.getPolygonCoords(props.userInput,props);return ___default.default.map(coords,function(coord){return "("+coord.join(", ")+")"}).join(" ")}static getAngleEquationString(props){if(props.userInput.type!=="angle"){throw makeInvalidTypeError("getAngleEquationString","angle")}const coords=InteractiveGraph.getAngleCoords(props.userInput,props);const allowReflexAngles=props.userInput.allowReflexAngles;const angle=getClockwiseAngle(coords,allowReflexAngles);return angle.toFixed(0)+"° angle"+" at ("+coords[1].join(", ")+")"}constructor(...args){super(...args),this.mafsRef=React__namespace.createRef();}}InteractiveGraph.defaultProps={labels:["x","y"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true},step:[1,1],backgroundImage:defaultBackgroundImage,markings:"graph",showTooltips:false,showProtractor:false,userInput:{type:"linear"}};function getUserInputFromSerializedState$8(serializedState){return serializedState.graph}function getStartUserInput$8(options){return options.graph}function getCorrectUserInput$3(options){return options.correct}var InteractiveGraph$1 = {name:"interactive-graph",displayName:"Interactive graph",widget:InteractiveGraph,getStartUserInput: getStartUserInput$8,getCorrectUserInput: getCorrectUserInput$3,getUserInputFromSerializedState: getUserInputFromSerializedState$8};
|
|
2050
2052
|
|
|
2051
2053
|
const bodyXsmallBold={fontFamily:"inherit",fontSize:15,fontWeight:"bold",lineHeight:"22px"};
|
|
2052
2054
|
|
|
@@ -2070,7 +2072,7 @@ const HACKY_CSS_CLASSNAME="perseus-widget-matcher";class Matcher extends React__
|
|
|
2070
2072
|
|
|
2071
2073
|
const getPromptJSON$8=renderProps=>{return {type:"matrix",options:{height:renderProps.matrixBoardSize[0],width:renderProps.matrixBoardSize[1]},userInput:{answerRows:renderProps.userInput.answers}}};
|
|
2072
2074
|
|
|
2073
|
-
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__namespace.Component{componentDidMount(){this.cursorPosition=[0,0];}getDOMNodeForPath(path){const inputID=getRefForPath$1(path);return ReactDOM__namespace.default.findDOMNode(this.refs[inputID])}getPromptJSON(){return getPromptJSON$8(this.props)}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,answers:userInput.answers}}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=perseusCore.getMatrixSize(this.props.userInput.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__default.default({"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}}),___default.default(maxRows).times(row=>{const rowVals=this.props.userInput.answers[row];return jsxRuntimeExports.jsx("div",{className:"matrix-row",children:___default.default(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 {const updatedProps={...inputProps,style:aphrodite.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.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.userInput.answers.map(answer=>[...answer]);if(!answers[row]){answers[row]=[];}answers[row][column]=value;this.props.handleUserInput({answers},cb);this.props.trackInteraction();};}}Matrix.contextType=PerseusI18nContext;Matrix.defaultProps={matrixBoardSize:[3,3],prefix:"",suffix:"",cursorPosition:[0,0],apiOptions:ApiOptions.defaults,linterContext:PerseusLinter.linterContextDefault,userInput:{answers:[[]]}};function
|
|
2075
|
+
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__namespace.Component{componentDidMount(){this.cursorPosition=[0,0];}getDOMNodeForPath(path){const inputID=getRefForPath$1(path);return ReactDOM__namespace.default.findDOMNode(this.refs[inputID])}getPromptJSON(){return getPromptJSON$8(this.props)}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,answers:userInput.answers}}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=perseusCore.getMatrixSize(this.props.userInput.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__default.default({"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}}),___default.default(maxRows).times(row=>{const rowVals=this.props.userInput.answers[row];return jsxRuntimeExports.jsx("div",{className:"matrix-row",children:___default.default(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 {const updatedProps={...inputProps,style:aphrodite.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.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.userInput.answers.map(answer=>[...answer]);if(!answers[row]){answers[row]=[];}answers[row][column]=value;this.props.handleUserInput({answers},cb);this.props.trackInteraction();};}}Matrix.contextType=PerseusI18nContext;Matrix.defaultProps={matrixBoardSize:[3,3],prefix:"",suffix:"",cursorPosition:[0,0],apiOptions:ApiOptions.defaults,linterContext:PerseusLinter.linterContextDefault,userInput:{answers:[[]]}};function getStartUserInput$5(){return {answers:[[]]}}function getCorrectUserInput$2(options){return {answers:options.answers.map(row=>row.map(num=>String(num)))}}function getUserInputFromSerializedState$5(serializedState){return {answers:serializedState.answers}}var Matrix$1 = {name:"matrix",displayName:"Matrix",hidden:true,widget:Matrix,isLintable:true,getStartUserInput: getStartUserInput$5,getCorrectUserInput: getCorrectUserInput$2,getUserInputFromSerializedState: getUserInputFromSerializedState$5};
|
|
2074
2076
|
|
|
2075
2077
|
const getPromptJSON$7=()=>{return getUnsupportedPromptJSON("measurer")};
|
|
2076
2078
|
|
|
@@ -2090,9 +2092,9 @@ const MovablePoint=Graphie.MovablePoint;const Line=Graphie.Line;const{assert: as
|
|
|
2090
2092
|
|
|
2091
2093
|
const getPromptJSON$5=renderProps=>{return {type:"orderer",options:{options:renderProps.options.map(option=>option.content)},userInput:{values:renderProps.userInput.current}}};
|
|
2092
2094
|
|
|
2093
|
-
class PlaceholderCard extends React__namespace.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__namespace.Component{render(){return jsxRuntimeExports.jsx("div",{className:"card-wrap",children:jsxRuntimeExports.jsx("div",{className:"card drag-hint"})})}}class Card extends React__namespace.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)));$__default.default(ReactDOM__namespace.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.",perseusCore.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?$__default.default.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;$__default.default(document).on("mousemove",this.onMouseMove);$__default.default(document).on("mouseup",this.onMouseUp);},this.unbindMouseMoveUp=()=>{this.mouseMoveUpBound=false;$__default.default(document).off("mousemove",this.onMouseMove);$__default.default(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:PerseusLinter.linterContextDefault};class Orderer extends React__namespace.Component{getPromptJSON(){return getPromptJSON$5(this.props)}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,current:userInput.current.map(e=>({content:e}))}}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.props.userInput.current.map((opt,i)=>{return jsxRuntimeExports.jsx(Card,{ref:"sortable"+i,fakeRef:"sortable"+i,floating:false,content:opt,linterContext:this.props.linterContext,onMouseDown:this.state.animating?$__default.default.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?$__default.default.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={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=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable));const list=this.props.userInput.current.slice();let opt;let placeholderIndex=null;if(type==="current"){list.splice(index,1);opt=this.props.userInput.current[index];placeholderIndex=index;}else if(type==="bank"){opt=this.props.options[index];}this.props.handleUserInput({current:list});this.setState({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.props.userInput.current.slice();if(!inCardBank){const newCard={content:this.state.dragContent,key:___default.default.uniqueId("perseus_draggable_card_"),width:this.state.dragWidth};list.splice(index,0,newCard.content);}this.props.handleUserInput({current:list});this.setState({dragging:false,placeholderIndex:null,animating:false});this.props.trackInteraction();};const offset=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable)).position();let finalOffset=null;if(inCardBank){this.props.options.forEach((opt,i)=>{if(opt.content===this.state.dragContent){const card=ReactDOM__namespace.default.findDOMNode(this.refs["bank"+i]);finalOffset=$__default.default(card).position();}});}else if(this.refs.placeholder!=null){finalOffset=$__default.default(ReactDOM__namespace.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.props.userInput.current);}this.setState({mousePos:loc,placeholderIndex:index});},this.findCorrectIndex=(draggable,list)=>{const isHorizontal=this.props.layout==="horizontal";const $dragList=$__default.default(ReactDOM__namespace.default.findDOMNode(this.refs.dragList));const leftEdge=$dragList.offset().left;const topEdge=$dragList.offset().top;const midWidth=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable)).offset().left-leftEdge;const midHeight=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable)).offset().top-topEdge;let index=0;let sumWidth=0;let sumHeight=0;if(isHorizontal){list.forEach((opt,i)=>{const card=ReactDOM__namespace.default.findDOMNode(this.refs["sortable"+i]);const outerWidth=$__default.default(card).outerWidth(true);if(midWidth>sumWidth+outerWidth/2){index+=1;}sumWidth+=outerWidth;});}else {list.forEach((_,i)=>{const card=ReactDOM__namespace.default.findDOMNode(this.refs["sortable"+i]);const outerHeight=$__default.default(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=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable));const $bank=$__default.default(ReactDOM__namespace.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=>{this.props.handleUserInput({current:values});};}}Orderer.defaultProps={options:[],height:"normal",layout:"horizontal",linterContext:PerseusLinter.linterContextDefault,userInput:{current:[]}};function getUserInputFromSerializedState$3(serializedState){return {current:serializedState.current.map(e=>e.content)}}function getStartUserInput$3(){return {current:[]}}var Orderer$1 = {name:"orderer",displayName:"Orderer",hidden:true,widget:Orderer,isLintable:true,getStartUserInput: getStartUserInput$3,getUserInputFromSerializedState: getUserInputFromSerializedState$3};
|
|
2095
|
+
class PlaceholderCard extends React__namespace.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__namespace.Component{render(){return jsxRuntimeExports.jsx("div",{className:"card-wrap",children:jsxRuntimeExports.jsx("div",{className:"card drag-hint"})})}}class Card extends React__namespace.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)));$__default.default(ReactDOM__namespace.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.",perseusCore.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?$__default.default.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;$__default.default(document).on("mousemove",this.onMouseMove);$__default.default(document).on("mouseup",this.onMouseUp);},this.unbindMouseMoveUp=()=>{this.mouseMoveUpBound=false;$__default.default(document).off("mousemove",this.onMouseMove);$__default.default(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:PerseusLinter.linterContextDefault};class Orderer extends React__namespace.Component{getPromptJSON(){return getPromptJSON$5(this.props)}getSerializedState(){const{userInput,...rest}=this.props;return {...rest,current:userInput.current.map(e=>({content:e}))}}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.props.userInput.current.map((opt,i)=>{return jsxRuntimeExports.jsx(Card,{ref:"sortable"+i,fakeRef:"sortable"+i,floating:false,content:opt,linterContext:this.props.linterContext,onMouseDown:this.state.animating?$__default.default.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?$__default.default.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={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=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable));const list=this.props.userInput.current.slice();let opt;let placeholderIndex=null;if(type==="current"){list.splice(index,1);opt=this.props.userInput.current[index];placeholderIndex=index;}else if(type==="bank"){opt=this.props.options[index];}this.props.handleUserInput({current:list});this.setState({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.props.userInput.current.slice();if(!inCardBank){const cardContent=this.state.dragContent;if(typeof cardContent==="string"){const newCard={content:cardContent,key:___default.default.uniqueId("perseus_draggable_card_"),width:this.state.dragWidth};list.splice(index,0,newCard.content);}}this.props.handleUserInput({current:list});this.setState({dragging:false,placeholderIndex:null,animating:false});this.props.trackInteraction();};const offset=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable)).position();let finalOffset=null;if(inCardBank){this.props.options.forEach((opt,i)=>{if(opt.content===this.state.dragContent){const card=ReactDOM__namespace.default.findDOMNode(this.refs["bank"+i]);finalOffset=$__default.default(card).position();}});}else if(this.refs.placeholder!=null){finalOffset=$__default.default(ReactDOM__namespace.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.props.userInput.current);}this.setState({mousePos:loc,placeholderIndex:index});},this.findCorrectIndex=(draggable,list)=>{const isHorizontal=this.props.layout==="horizontal";const $dragList=$__default.default(ReactDOM__namespace.default.findDOMNode(this.refs.dragList));const leftEdge=$dragList.offset().left;const topEdge=$dragList.offset().top;const midWidth=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable)).offset().left-leftEdge;const midHeight=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable)).offset().top-topEdge;let index=0;let sumWidth=0;let sumHeight=0;if(isHorizontal){list.forEach((opt,i)=>{const card=ReactDOM__namespace.default.findDOMNode(this.refs["sortable"+i]);const outerWidth=$__default.default(card).outerWidth(true);if(midWidth>sumWidth+outerWidth/2){index+=1;}sumWidth+=outerWidth;});}else {list.forEach((_,i)=>{const card=ReactDOM__namespace.default.findDOMNode(this.refs["sortable"+i]);const outerHeight=$__default.default(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=$__default.default(ReactDOM__namespace.default.findDOMNode(draggable));const $bank=$__default.default(ReactDOM__namespace.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=>{this.props.handleUserInput({current:values});};}}Orderer.defaultProps={options:[],height:"normal",layout:"horizontal",linterContext:PerseusLinter.linterContextDefault,userInput:{current:[]}};function getUserInputFromSerializedState$3(serializedState){return {current:serializedState.current.map(e=>e.content)}}function getStartUserInput$3(){return {current:[]}}var Orderer$1 = {name:"orderer",displayName:"Orderer",hidden:true,widget:Orderer,isLintable:true,getStartUserInput: getStartUserInput$3,getUserInputFromSerializedState: getUserInputFromSerializedState$3};
|
|
2094
2096
|
|
|
2095
|
-
class PassageRefTarget extends React__namespace.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;}}PassageRefTarget.contextType=PerseusI18nContext;PassageRefTarget.defaultProps={content:"",linterContext:PerseusLinter.linterContextDefault};var PassageRefTarget$1 = {name:"passage-ref-target",displayName:"PassageRefTarget",widget:PassageRefTarget,hidden:true,
|
|
2097
|
+
class PassageRefTarget extends React__namespace.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;}}PassageRefTarget.contextType=PerseusI18nContext;PassageRefTarget.defaultProps={content:"",linterContext:PerseusLinter.linterContextDefault};var PassageRefTarget$1 = {name:"passage-ref-target",displayName:"PassageRefTarget",widget:PassageRefTarget,hidden:true,isLintable:true};
|
|
2096
2098
|
|
|
2097
2099
|
const getPromptJSON$4=()=>{return getUnsupportedPromptJSON("phet-simulation")};
|
|
2098
2100
|
|
|
@@ -2100,7 +2102,7 @@ const MOBILE_APP_BOTTOM_BAR_HEIGHT=66;class PhetSimulation extends React__namesp
|
|
|
2100
2102
|
|
|
2101
2103
|
const getPromptJSON$3=()=>{return getUnsupportedPromptJSON("plotter")};
|
|
2102
2104
|
|
|
2103
|
-
class Plotter extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.setupGraphie(this.props.userInput);}UNSAFE_componentWillReceiveProps(nextProps){const props=["type","labels","categories","scaleY","maxY","snapsPerLine","picUrl","labelInterval","static"];this.shouldSetupGraphie=___default.default.any(props,prop=>!___default.default.isEqual(this.props[prop],nextProps[prop]),this);if(!___default.default.isEqual(this.props.starting,nextProps.starting)&&!___default.default.isEqual(this.props.userInput,nextProps.starting)){this.shouldSetupGraphie=true;this.props.handleUserInput(nextProps.starting);}}componentDidUpdate(prevProps,prevState){this.shouldSetupGraphie=this.shouldSetupGraphie||!___default.default.isEqual(this.state.categoryHeights,prevState.categoryHeights);if(this.shouldSetupGraphie){this.setupGraphie(prevProps.userInput);}}componentWillUnmount(){this._isMounted=false;}setupGraphie(prevValues){const self=this;self.shouldSetupGraphie=false;$__default.default(this.graphieDiv.current).empty();const graphie=GraphUtils.createGraphie(this.graphieDiv.current);self.graphie=graphie;self.graphie.pics=[];self.graphie.dotTicks=[];const isBar=self.props.type==="bar";const isLine=self.props.type==="line";const isPic=self.props.type==="pic";const isHistogram=self.props.type==="histogram";const isDotplot=self.props.type==="dotplot";const isTiledPlot=isPic||isDotplot;const config={};const c=config;const isMobile=this.props.apiOptions.isMobile;c.graph={lines:[],bars:[],points:[],dividers:[]};c.scaleY=self.props.scaleY;c.dimX=self.props.categories.length;const plotDimensions=isMobile?[288,336]:self.props.plotDimensions;if(isLine){c.dimX+=isMobile?-0.2:1;}else if(isHistogram){c.barPad=0;c.barWidth=1;}else if(isBar){c.barPad=isMobile?.08:.15;c.barWidth=1-2*c.barPad;c.dimX+=(isMobile?-2:2)*c.barPad;}else if(isTiledPlot){c.picBoxHeight=self.props.picBoxHeight;c.picBoxWidthPx=plotDimensions[0]/self.props.categories.length;const picPadAllWidth=plotDimensions[0]-c.dimX*c.picBoxWidthPx;c.picPad=picPadAllWidth/(2*c.dimX+2);const picFullWidth=c.picBoxWidthPx+2*c.picPad;c.picPad=c.picPad/picFullWidth;c.picBoxWidth=c.picBoxWidthPx/picFullWidth;c.dimX+=2*c.picPad;}if(isDotplot){c.picBoxHeight=this.DOT_PLOT_POINT_SIZE()*2+this.DOT_PLOT_POINT_PADDING();}c.dimY=Math.ceil(self.props.maxY/c.scaleY)*c.scaleY;let padX=25;if((isBar||isLine)&&isMobile){padX=self.props.labels[1].length!==0?17:11;}if(isDotplot){padX/=2;}if(isMobile&&isTiledPlot&&self.props.labels[1].length===0){padX=0;}let padTop=25;let padBottom=25*3;if(isMobile&&(isBar||isTiledPlot)){const maxCategoryHeight=Math.max(0,...Object.values(self.state.categoryHeights));if(maxCategoryHeight){let offsetY=25;if(isTiledPlot){offsetY+=10;}padBottom=offsetY+maxCategoryHeight;}}if(isMobile){c.scale=[(plotDimensions[0]-padX*4)/c.dimX,(plotDimensions[1]-(padTop+padBottom))/c.dimY];}else {c.scale=___default.default.map([c.dimX,c.dimY],function(dim,i){return plotDimensions[i]/dim});}if(isTiledPlot){c.scale[1]=c.picBoxHeight/c.scaleY;}padX/=c.scale[0];padTop/=c.scale[1];padBottom/=c.scale[1];graphie.init({range:[[-3*padX,c.dimX+padX],[-padBottom,c.dimY+padTop]],scale:c.scale,isMobile:this.props.apiOptions.isMobile});graphie.addMouseLayer({allowScratchpad:true,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable});if(!isTiledPlot){const initialY=isMobile?c.scaleY:0;for(let y=initialY;y<=c.dimY;y+=c.scaleY){graphie.label([0,y],kmath.KhanMath.roundToApprox(y,2),"left",true);graphie.style({stroke:isMobile?"#e9ebec":"#000",strokeWidth:1,opacity:isMobile?1:.3},function(){graphie.line([0,y],[c.dimX,y]);});}}if((isBar||isLine)&&isMobile&&!this.props.static){self.graphie.dragPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.dragHandles,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}self.setupCategories(config);if(isTiledPlot&&isMobile){self.graphie.dotPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.tapAddPoints,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}if(isTiledPlot){self.drawPicHeights(self.props.userInput,prevValues);}graphie.style({stroke:"#000",strokeWidth:2,opacity:1},function(){if(isTiledPlot){if(isDotplot){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?0:.5,0],[c.dimX-(isMobile?0:.5),0]));}else {graphie.line([0,0],[c.dimX,0]);if(self.props.labels[1].length!==0||!isMobile){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}}else {graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?-padX*3:0,0],[c.dimX+(isMobile?padX:0),0]));if(!((isBar||isLine)&&isMobile)){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}});graphie.label([c.dimX/2,isMobile?-padBottom:-35/c.scale[1]],self.props.labels[0],isMobile?"above":"below",false).css("font-weight","bold").css("color",isMobile&&KhanColors.GRAY_F);graphie.label([(isMobile?-35:-60)/c.scale[0],c.dimY/2],self.props.labels[1],"center",false).css("font-weight","bold").css("color",isMobile&&KhanColors.GRAY_F).addClass("rotate");if(this.props.apiOptions.isMobile){this.horizHairline=new WrappedLine(this.graphie,[0,0],[0,0],{normalStyle:{strokeWidth:1}});this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.hairlineRange=[[0,c.dimX],[0,c.dimY]];}}_testInsertUserInput(userInput){this.props.handleUserInput(userInput);}drawPicHeights(values,prevValues){const self=this;const graphie=self.graphie;const pics=graphie.pics;const isMobile=this.props.apiOptions.isMobile;if(isMobile){const shouldDisplay=values.every(v=>v===0);graphie.dotPrompt[0].style.display=shouldDisplay?"inline":"none";}___default.default.each(pics,function(ps,i){___default.default.each(ps,function(pic,j){const y=(j+1)*self.props.scaleY;const show=y<=values[i];if(self.props.type==="dotplot"){const wasShown=y<=prevValues[i];const wasJustShown=show&&!wasShown;if(wasJustShown){pic.animate({"stroke-width":8},75,()=>pic.animate({"stroke-width":2},75));}}$__default.default(pic[0]).css({display:show?"inline":"none"});graphie.dotTicks[i][j][0].style.display=show||!isMobile?"none":"inline";});});}getPromptJSON(){return getPromptJSON$3()}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,values:this.props.userInput}}render(){const paddingForBottomLabel=75;const style={marginBottom:this.props.labels[0]?paddingForBottomLabel:0};return jsxRuntimeExports.jsx("div",{className:"perseus-widget-plotter graphie",ref:this.graphieDiv,style:style})}constructor(...args){super(...args),this._isMounted=false,this.graphieDiv=React__namespace.createRef(),this.state={categoryHeights:{}},this.DOT_PLOT_POINT_SIZE=()=>{return this.props.apiOptions.isMobile?6:4},this.DOT_PLOT_POINT_PADDING=()=>{return 8},this.DOT_TICK_POINT_SIZE=()=>{return 2},this.showHairlines=point=>{if(this.props.apiOptions.isMobile){this.horizHairline.moveTo([this.hairlineRange[0][0],point[1]],[this.hairlineRange[0][1],point[1]]);this.horizHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();}},this.labelCategory=(x,category)=>{const isMobile=this.props.apiOptions.isMobile;const graphie=this.graphie;category=category+"";let isTeX=false;const mathyCategory=category.match(/^\$(.*)\$$/);if(mathyCategory){category=mathyCategory[1];isTeX=true;}const translateX=5;const rotationDeg=45;const rotationRad=rotationDeg*(Math.PI/180);const labelRotation=`translateX(-50%) translateX(${translateX}px) `+`translateY(-50%) rotate(-${rotationDeg}deg)`;const shouldRotate=isMobile&&!mathyCategory;return new Promise(resolve=>{graphie.style({color:isMobile?KhanColors.GRAY_G:"inherit",transform:shouldRotate?labelRotation:"none",transformOrigin:"100%"},()=>{const $span=graphie.label([x,isMobile?-0.5:0],category,"below",isTeX);const height=14+(shouldRotate?Math.round($span.height()*Math.cos(rotationRad)+($span.width()+translateX)*Math.sin(rotationRad)):$span.height());resolve({category,height});});})},this.setupCategories=config=>{const self=this;const c=config;const graphie=self.graphie;const isMobile=this.props.apiOptions.isMobile;const categoryHeightPromises=[];if(self.props.type==="histogram"){___default.default.times(self.props.categories.length-1,function(i){self.setupBar({index:i,startHeight:self.props.userInput[i],config:config,isHistogram:true});});___default.default.each(self.props.categories,function(category,i){const x=.5+i*c.barWidth;categoryHeightPromises.push(self.labelCategory(x,category));const tickHeight=6/c.scale[1];graphie.style({stroke:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,-tickHeight],[x,0]);});});}else {___default.default.each(self.props.categories,function(category,i){const startHeight=self.props.userInput[i];let x;if(self.props.type==="bar"){x=self.setupBar({index:i,startHeight:startHeight,config:config,isHistogram:false});}else if(self.props.type==="line"){x=self.setupLine(i,startHeight,config);}else if(self.props.type==="pic"){x=self.setupPic(i,config);}else if(self.props.type==="dotplot"){x=self.setupDotplot(i,config);}let tickStart=0;let tickEnd=-6/c.scale[1];if(self.props.type==="dotplot"&&!isMobile){tickStart=-tickEnd;}if(self.props.type==="dotplot"){if(i%self.props.labelInterval===0||i===self.props.categories.length-1){categoryHeightPromises.push(self.labelCategory(x,category));tickStart*=1.5;tickEnd*=1.5;}}else {categoryHeightPromises.push(self.labelCategory(x,category));}graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,tickStart],[x,tickEnd]);});});}Promise.all(categoryHeightPromises).then(measurements=>{if(self._isMounted){const categoryHeights={};measurements.forEach(({category,height})=>categoryHeights[category]=height);self.setState({categoryHeights});}});},this._clampValue=(v,min,max)=>{return Math.max(Math.min(v,max),min)},this._maybeShowDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="inline";}},this._maybeHideDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="none";}},this.setupBar=args=>{const isMobile=this.props.apiOptions.isMobile;const i=args.index;const startHeight=args.startHeight;const config=args.config;const isHistogram=args.isHistogram;const self=this;const graphie=self.graphie;const barHalfWidth=config.barWidth/2;let x;if(isHistogram){x=.5+i*config.barWidth+barHalfWidth;}else {x=(isMobile?barHalfWidth:.5+config.barPad)+i;}const scaleBar=function(i,height){const center=graphie.scalePoint(0);config.graph.bars[i].scale(1,Math.max(isMobile?.2:.01,height/config.scaleY),center[0],center[1]);if(isHistogram){const leftDivider=config.graph.dividers[i-1];const rightDivider=config.graph.dividers[i];if(leftDivider){const divHeight=Math.min(self.props.userInput[i-1],height);leftDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}if(rightDivider){const divHeight=Math.min(self.props.userInput[i+1],height);rightDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}}};graphie.style({stroke:"none",fill:isMobile?KhanColors.BLUE_C:KhanColors.LIGHT_BLUE,opacity:1},function(){config.graph.bars[i]=graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY],[x+barHalfWidth,config.scaleY],[x+barHalfWidth,0],[x-barHalfWidth,0]]);});if(isHistogram){if(i>0){graphie.style({stroke:"#000",strokeWidth:1,opacity:.3},function(){config.graph.dividers.push(graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY]]));});}}if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;config.graph.lines[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMoveStart:function(){config.graph.bars[i].attr({fill:KhanColors.INTERACTIVE});},onMove:function(){const y=config.graph.lines[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();scaleBar(i,y);},onMoveEnd:function(){config.graph.bars[i].attr({fill:KhanColors.BLUE_C});}});config.graph.lines[i].state.visibleShape.wrapper.style.zIndex="1";self._maybeShowDragPrompt();}else {config.graph.lines[i]=graphie.addMovableLineSegment({coordA:[x-barHalfWidth,startHeight],coordZ:[x+barHalfWidth,startHeight],snapY:config.scaleY/self.props.snapsPerLine,constraints:{constrainX:true},normalStyle:{stroke:KhanColors.INTERACTIVE,"stroke-width":this.props.static?0:4}});config.graph.lines[i].onMove=function(dx,dy){let y=this.coordA[1];if(y<0||y>config.dimY){y=Math.min(Math.max(y,0),config.dimY);this.coordA[1]=this.coordZ[1]=y;this.transform();}const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);scaleBar(i,y);};}scaleBar(i,startHeight);return x},this.setupLine=(i,startHeight,config)=>{const isMobile=this.props.apiOptions.isMobile;const self=this;const c=config;const graphie=self.graphie;const x=i+(isMobile?.4:1);if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;c.graph.points[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMove:function(){const y=c.graph.points[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();}});self._maybeShowDragPrompt();if(i>0){c.graph.lines[i]=Interactive2.addMovableLine(graphie,{points:[c.graph.points[i-1],c.graph.points[i]],constraints:Interactive2.MovablePoint.constraints.fixed(),normalStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2},highlightStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2}});}}else {c.graph.points[i]=graphie.addMovablePoint({coord:[x,startHeight],constraints:{constrainX:true},normalStyle:{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE},snapY:c.scaleY/self.props.snapsPerLine});c.graph.points[i].onMove=function(x,y){y=Math.min(Math.max(y,0),c.dimY);const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);return [x,y]};if(i>0){c.graph.lines[i]=graphie.addMovableLineSegment({pointA:c.graph.points[i-1],pointZ:c.graph.points[i],constraints:{fixed:true},normalStyle:{stroke:"#9ab8ed","stroke-width":2}});}}return x},this.setupDotplot=(i,config)=>{const graphie=this.graphie;const isMobile=this.props.apiOptions.isMobile;return this.setupTiledPlot(i,isMobile?.5:1,config,(x,y)=>{return graphie.ellipse([x,y],[this.DOT_PLOT_POINT_SIZE()/graphie.scale[0],this.DOT_PLOT_POINT_SIZE()/graphie.scale[1]],{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE})})},this.setupPic=(i,config)=>{const graphie=this.graphie;return this.setupTiledPlot(i,0,config,(x,y)=>{const scaledCenter=graphie.scalePoint([x,y]);const size=this.props.picSize;return graphie.raphael.image(this.props.picUrl,scaledCenter[0]-size/2,scaledCenter[1]-size/2,size,size)})},this.setupTiledPlot=(i,bottomMargin,config,createImage)=>{const self=this;const c=config;const graphie=self.graphie;const pics=graphie.pics;const dotTicks=graphie.dotTicks;const x=i+.5+c.picPad;graphie.mouselayer.canvas.style.touchAction="none";pics[i]=[];dotTicks[i]=[];const n=Math.round(c.dimY/c.scaleY)+1;___default.default(n).times(function(j){j-=1;const midY=(j+.5)*c.scaleY;const leftX=x-c.picBoxWidth/2;const topY=midY+.5*c.scaleY;const coord=graphie.scalePoint([leftX,topY+bottomMargin]);const mouseRect=graphie.mouselayer.rect(coord[0],coord[1],c.picBoxWidthPx,c.picBoxHeight);$__default.default(mouseRect[0]).css({fill:"#000",opacity:0,cursor:"pointer"}).on("vmousedown",function(e){e.preventDefault();self.whichPicClicked=i;self.setPicHeight(i,topY);$__default.default(document).on("vmouseup.plotTile",function(e){$__default.default(document).unbind(".plotTile");});$__default.default(document).on("vmousemove.plotTile",function(e){e.preventDefault();const yCoord=graphie.getMouseCoord(e)[1];const adjustedCoord=Math.floor(yCoord-bottomMargin);const newJ=Math.max(-1,Math.floor(adjustedCoord/c.scaleY));const newMidY=(newJ+.5)*c.scaleY;const newTopY=Math.min(newMidY+.5*c.scaleY,c.dimY);self.setPicHeight(self.whichPicClicked,newTopY);});});if(j<0){return}pics[i][j]=createImage(x,midY+bottomMargin);dotTicks[i][j]=graphie.ellipse([x,midY+bottomMargin],[self.DOT_TICK_POINT_SIZE()/graphie.scale[0],self.DOT_TICK_POINT_SIZE()/graphie.scale[1]],{fill:"#dee1e3",stroke:"#dee1e3"});});return x},this.setPicHeight=(i,y)=>{const values=[...this.props.userInput];values[i]=y;this.drawPicHeights(values,this.props.userInput);this.changeAndTrack(values);},this.changeAndTrack=userInput=>{this.props.handleUserInput(userInput);this.props.trackInteraction();};}}Plotter.contextType=PerseusI18nContext;Plotter.defaultProps={type:"bar",labels:["",""],categories:[""],scaleY:1,maxY:10,snapsPerLine:2,picSize:40,picBoxHeight:48,picUrl:"",plotDimensions:[380,300],labelInterval:1};function getStartUserInput$2(options){return options.starting}function getCorrectUserInput(options){return options.correct}function getUserInputFromSerializedState$2(serializedState){return serializedState.values}var Plotter$1 = {name:"plotter",displayName:"Plotter",hidden:true,widget:Plotter,getCorrectUserInput,staticTransform:___default.default.identity,getStartUserInput: getStartUserInput$2,getUserInputFromSerializedState: getUserInputFromSerializedState$2};
|
|
2105
|
+
class Plotter extends React__namespace.Component{componentDidMount(){this._isMounted=true;this.setupGraphie(this.props.userInput);}UNSAFE_componentWillReceiveProps(nextProps){const props=["type","labels","categories","scaleY","maxY","snapsPerLine","picUrl","labelInterval","static"];this.shouldSetupGraphie=___default.default.any(props,prop=>!___default.default.isEqual(this.props[prop],nextProps[prop]),this);if(!___default.default.isEqual(this.props.starting,nextProps.starting)&&!___default.default.isEqual(this.props.userInput,nextProps.starting)){this.shouldSetupGraphie=true;this.props.handleUserInput(nextProps.starting);}}componentDidUpdate(prevProps,prevState){this.shouldSetupGraphie=this.shouldSetupGraphie||!___default.default.isEqual(this.state.categoryHeights,prevState.categoryHeights);if(this.shouldSetupGraphie){this.setupGraphie(prevProps.userInput);}}componentWillUnmount(){this._isMounted=false;}setupGraphie(prevValues){const self=this;self.shouldSetupGraphie=false;$__default.default(this.graphieDiv.current).empty();const graphie=GraphUtils.createGraphie(this.graphieDiv.current);self.graphie=graphie;self.graphie.pics=[];self.graphie.dotTicks=[];const isBar=self.props.type==="bar";const isLine=self.props.type==="line";const isPic=self.props.type==="pic";const isHistogram=self.props.type==="histogram";const isDotplot=self.props.type==="dotplot";const isTiledPlot=isPic||isDotplot;const config={};const c=config;const isMobile=this.props.apiOptions.isMobile;c.graph={lines:[],bars:[],points:[],dividers:[]};c.scaleY=self.props.scaleY;c.dimX=self.props.categories.length;const plotDimensions=isMobile?[288,336]:self.props.plotDimensions;if(isLine){c.dimX+=isMobile?-0.2:1;}else if(isHistogram){c.barPad=0;c.barWidth=1;}else if(isBar){c.barPad=isMobile?.08:.15;c.barWidth=1-2*c.barPad;c.dimX+=(isMobile?-2:2)*c.barPad;}else if(isTiledPlot){c.picBoxHeight=self.props.picBoxHeight;c.picBoxWidthPx=plotDimensions[0]/self.props.categories.length;const picPadAllWidth=plotDimensions[0]-c.dimX*c.picBoxWidthPx;c.picPad=picPadAllWidth/(2*c.dimX+2);const picFullWidth=c.picBoxWidthPx+2*c.picPad;c.picPad=c.picPad/picFullWidth;c.picBoxWidth=c.picBoxWidthPx/picFullWidth;c.dimX+=2*c.picPad;}if(isDotplot){c.picBoxHeight=this.DOT_PLOT_POINT_SIZE()*2+this.DOT_PLOT_POINT_PADDING();}c.dimY=Math.ceil(self.props.maxY/c.scaleY)*c.scaleY;let padX=25;if((isBar||isLine)&&isMobile){padX=self.props.labels[1].length!==0?17:11;}if(isDotplot){padX/=2;}if(isMobile&&isTiledPlot&&self.props.labels[1].length===0){padX=0;}let padTop=25;let padBottom=25*3;if(isMobile&&(isBar||isTiledPlot)){const maxCategoryHeight=Math.max(0,...Object.values(self.state.categoryHeights));if(maxCategoryHeight){let offsetY=25;if(isTiledPlot){offsetY+=10;}padBottom=offsetY+maxCategoryHeight;}}if(isMobile){c.scale=[(plotDimensions[0]-padX*4)/c.dimX,(plotDimensions[1]-(padTop+padBottom))/c.dimY];}else {c.scale=___default.default.map([c.dimX,c.dimY],function(dim,i){return plotDimensions[i]/dim});}if(isTiledPlot){c.scale[1]=c.picBoxHeight/c.scaleY;}padX/=c.scale[0];padTop/=c.scale[1];padBottom/=c.scale[1];graphie.init({range:[[-3*padX,c.dimX+padX],[-padBottom,c.dimY+padTop]],scale:c.scale,isMobile:this.props.apiOptions.isMobile});graphie.addMouseLayer({allowScratchpad:true,setDrawingAreaAvailable:this.props.apiOptions.setDrawingAreaAvailable});if(!isTiledPlot){const initialY=isMobile?c.scaleY:0;for(let y=initialY;y<=c.dimY;y+=c.scaleY){graphie.label([0,y],kmath.KhanMath.roundToApprox(y,2),"left",true);graphie.style({stroke:isMobile?"#e9ebec":"#000",strokeWidth:1,opacity:isMobile?1:.3},function(){graphie.line([0,y],[c.dimX,y]);});}}if((isBar||isLine)&&isMobile&&!this.props.static){self.graphie.dragPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.dragHandles,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}self.setupCategories(config);if(isTiledPlot&&isMobile){self.graphie.dotPrompt=graphie.label([c.dimX/2,c.dimY/2],this.context.strings.tapAddPoints,"center",false).css("font-weight","bold").css("color",KhanColors.KA_GREEN).css("display","none");}if(isTiledPlot){self.drawPicHeights(self.props.userInput,prevValues);}graphie.style({stroke:"#000",strokeWidth:2,opacity:1},function(){if(isTiledPlot){if(isDotplot){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?0:.5,0],[c.dimX-(isMobile?0:.5),0]));}else {graphie.line([0,0],[c.dimX,0]);if(self.props.labels[1].length!==0||!isMobile){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}}else {graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([isMobile?-padX*3:0,0],[c.dimX+(isMobile?padX:0),0]));if(!((isBar||isLine)&&isMobile)){graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2},()=>graphie.line([0,0],[0,c.dimY]));}}});graphie.label([c.dimX/2,isMobile?-padBottom:-35/c.scale[1]],self.props.labels[0],isMobile?"above":"below",false).css("font-weight","bold").css("color",isMobile&&KhanColors.GRAY_F);graphie.label([(isMobile?-35:-60)/c.scale[0],c.dimY/2],self.props.labels[1],"center",false).css("font-weight","bold").css("color",isMobile&&KhanColors.GRAY_F).addClass("rotate");if(this.props.apiOptions.isMobile){this.horizHairline=new WrappedLine(this.graphie,[0,0],[0,0],{normalStyle:{strokeWidth:1}});this.horizHairline.attr({stroke:KhanColors.INTERACTIVE});this.horizHairline.hide();this.hairlineRange=[[0,c.dimX],[0,c.dimY]];}}_testInsertUserInput(userInput){this.props.handleUserInput(userInput);}drawPicHeights(values,prevValues){const self=this;const graphie=self.graphie;const pics=graphie.pics;const isMobile=this.props.apiOptions.isMobile;if(isMobile){const shouldDisplay=values.every(v=>v===0);graphie.dotPrompt[0].style.display=shouldDisplay?"inline":"none";}___default.default.each(pics,function(ps,i){___default.default.each(ps,function(pic,j){const y=(j+1)*self.props.scaleY;const show=y<=values[i];if(self.props.type==="dotplot"){const wasShown=y<=prevValues[i];const wasJustShown=show&&!wasShown;if(wasJustShown){pic.animate({"stroke-width":8},75,()=>pic.animate({"stroke-width":2},75));}}$__default.default(pic[0]).css({display:show?"inline":"none"});graphie.dotTicks[i][j][0].style.display=show||!isMobile?"none":"inline";});});}getPromptJSON(){return getPromptJSON$3()}getSerializedState(){const{userInput:_,...rest}=this.props;return {...rest,values:this.props.userInput}}render(){const paddingForBottomLabel=75;const style={marginBottom:this.props.labels[0]?paddingForBottomLabel:0};return jsxRuntimeExports.jsx("div",{className:"perseus-widget-plotter graphie",ref:this.graphieDiv,style:style})}constructor(...args){super(...args),this._isMounted=false,this.graphieDiv=React__namespace.createRef(),this.state={categoryHeights:{}},this.DOT_PLOT_POINT_SIZE=()=>{return this.props.apiOptions.isMobile?6:4},this.DOT_PLOT_POINT_PADDING=()=>{return 8},this.DOT_TICK_POINT_SIZE=()=>{return 2},this.showHairlines=point=>{if(this.props.apiOptions.isMobile){this.horizHairline.moveTo([this.hairlineRange[0][0],point[1]],[this.hairlineRange[0][1],point[1]]);this.horizHairline.show();}},this.hideHairlines=()=>{if(this.props.apiOptions.isMobile){this.horizHairline.hide();}},this.labelCategory=(x,category)=>{const isMobile=this.props.apiOptions.isMobile;const graphie=this.graphie;category=category+"";let isTeX=false;const mathyCategory=category.match(/^\$(.*)\$$/);if(mathyCategory){category=mathyCategory[1];isTeX=true;}const translateX=5;const rotationDeg=45;const rotationRad=rotationDeg*(Math.PI/180);const labelRotation=`translateX(-50%) translateX(${translateX}px) `+`translateY(-50%) rotate(-${rotationDeg}deg)`;const shouldRotate=isMobile&&!mathyCategory;return new Promise(resolve=>{graphie.style({color:isMobile?KhanColors.GRAY_G:"inherit",transform:shouldRotate?labelRotation:"none",transformOrigin:"100%"},()=>{const $span=graphie.label([x,isMobile?-0.5:0],category,"below",isTeX);const height=14+(shouldRotate?Math.round($span.height()*Math.cos(rotationRad)+($span.width()+translateX)*Math.sin(rotationRad)):$span.height());resolve({category,height});});})},this.setupCategories=config=>{const self=this;const c=config;const graphie=self.graphie;const isMobile=this.props.apiOptions.isMobile;const categoryHeightPromises=[];if(self.props.type==="histogram"){___default.default.times(self.props.categories.length-1,function(i){self.setupBar({index:i,startHeight:self.props.userInput[i],config:config,isHistogram:true});});___default.default.each(self.props.categories,function(category,i){const x=.5+i*c.barWidth;categoryHeightPromises.push(self.labelCategory(x,category));const tickHeight=6/c.scale[1];graphie.style({stroke:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,-tickHeight],[x,0]);});});}else {___default.default.each(self.props.categories,function(category,i){const startHeight=self.props.userInput[i];let x;if(self.props.type==="bar"){x=self.setupBar({index:i,startHeight:startHeight,config:config,isHistogram:false});}else if(self.props.type==="line"){x=self.setupLine(i,startHeight,config);}else if(self.props.type==="pic"){x=self.setupPic(i,config);}else if(self.props.type==="dotplot"){x=self.setupDotplot(i,config);}let tickStart=0;let tickEnd=-6/c.scale[1];if(self.props.type==="dotplot"&&!isMobile){tickStart=-tickEnd;}if(self.props.type==="dotplot"){if(i%self.props.labelInterval===0||i===self.props.categories.length-1){categoryHeightPromises.push(self.labelCategory(x,category));tickStart*=1.5;tickEnd*=1.5;}}else {categoryHeightPromises.push(self.labelCategory(x,category));}graphie.style({stroke:isMobile?KhanColors.GRAY_G:"#000",strokeWidth:isMobile?1:2,opacity:1},function(){graphie.line([x,tickStart],[x,tickEnd]);});});}Promise.all(categoryHeightPromises).then(measurements=>{if(self._isMounted){const categoryHeights={};measurements.forEach(({category,height})=>categoryHeights[category]=height);self.setState({categoryHeights});}});},this._clampValue=(v,min,max)=>{return Math.max(Math.min(v,max),min)},this._maybeShowDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="inline";}},this._maybeHideDragPrompt=()=>{if(this.graphie.dragPrompt!=null){this.graphie.dragPrompt[0].style.display="none";}},this.setupBar=args=>{const isMobile=this.props.apiOptions.isMobile;const i=args.index;const startHeight=args.startHeight;const config=args.config;const isHistogram=args.isHistogram;const self=this;const graphie=self.graphie;const barHalfWidth=config.barWidth/2;let x;if(isHistogram){x=.5+i*config.barWidth+barHalfWidth;}else {x=(isMobile?barHalfWidth:.5+config.barPad)+i;}const scaleBar=function(i,height){const center=graphie.scalePoint(0);config.graph.bars[i].scale(1,Math.max(isMobile?.2:.01,height/config.scaleY),center[0],center[1]);if(isHistogram){const leftDivider=config.graph.dividers[i-1];const rightDivider=config.graph.dividers[i];if(leftDivider){const divHeight=Math.min(self.props.userInput[i-1],height);leftDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}if(rightDivider){const divHeight=Math.min(self.props.userInput[i+1],height);rightDivider.scale(1,Math.max(.01,divHeight/config.scaleY),center[0],center[1]);}}};graphie.style({stroke:"none",fill:isMobile?KhanColors.BLUE_C:KhanColors.LIGHT_BLUE,opacity:1},function(){config.graph.bars[i]=graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY],[x+barHalfWidth,config.scaleY],[x+barHalfWidth,0],[x-barHalfWidth,0]]);});if(isHistogram){if(i>0){graphie.style({stroke:"#000",strokeWidth:1,opacity:.3},function(){config.graph.dividers.push(graphie.path([[x-barHalfWidth,0],[x-barHalfWidth,config.scaleY]]));});}}if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;config.graph.lines[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMoveStart:function(){config.graph.bars[i].attr({fill:KhanColors.INTERACTIVE});},onMove:function(){const y=config.graph.lines[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();scaleBar(i,y);},onMoveEnd:function(){config.graph.bars[i].attr({fill:KhanColors.BLUE_C});}});config.graph.lines[i].state.visibleShape.wrapper.style.zIndex="1";self._maybeShowDragPrompt();}else {config.graph.lines[i]=graphie.addMovableLineSegment({coordA:[x-barHalfWidth,startHeight],coordZ:[x+barHalfWidth,startHeight],snapY:config.scaleY/self.props.snapsPerLine,constraints:{constrainX:true},normalStyle:{stroke:KhanColors.INTERACTIVE,"stroke-width":this.props.static?0:4}});config.graph.lines[i].onMove=function(dx,dy){let y=this.coordA[1];if(y<0||y>config.dimY){y=Math.min(Math.max(y,0),config.dimY);this.coordA[1]=this.coordZ[1]=y;this.transform();}const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);scaleBar(i,y);};}scaleBar(i,startHeight);return x},this.setupLine=(i,startHeight,config)=>{const isMobile=this.props.apiOptions.isMobile;const self=this;const c=config;const graphie=self.graphie;const x=i+(isMobile?.4:1);if(isMobile){const snap=config.scaleY/self.props.snapsPerLine;c.graph.points[i]=Interactive2.addMaybeMobileMovablePoint(this,{coord:[x,startHeight],constraints:[(coord,prev,options)=>{return [x,this._clampValue(Math.round(coord[1]/snap)*snap,0,config.dimY)]}],onMove:function(){const y=c.graph.points[i].coord()[1];const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);self._maybeHideDragPrompt();}});self._maybeShowDragPrompt();if(i>0){c.graph.lines[i]=Interactive2.addMovableLine(graphie,{points:[c.graph.points[i-1],c.graph.points[i]],constraints:Interactive2.MovablePoint.constraints.fixed(),normalStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2},highlightStyle:{stroke:KhanColors.BLUE_C,"stroke-width":2}});}}else {c.graph.points[i]=graphie.addMovablePoint({coord:[x,startHeight],constraints:{constrainX:true},normalStyle:{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE},snapY:c.scaleY/self.props.snapsPerLine});c.graph.points[i].onMove=function(x,y){y=Math.min(Math.max(y,0),c.dimY);const values=[...self.props.userInput];values[i]=y;self.changeAndTrack(values);return [x,y]};if(i>0){c.graph.lines[i]=graphie.addMovableLineSegment({pointA:c.graph.points[i-1],pointZ:c.graph.points[i],constraints:{fixed:true},normalStyle:{stroke:"#9ab8ed","stroke-width":2}});}}return x},this.setupDotplot=(i,config)=>{const graphie=this.graphie;const isMobile=this.props.apiOptions.isMobile;return this.setupTiledPlot(i,isMobile?.5:1,config,(x,y)=>{return graphie.ellipse([x,y],[this.DOT_PLOT_POINT_SIZE()/graphie.scale[0],this.DOT_PLOT_POINT_SIZE()/graphie.scale[1]],{fill:KhanColors.INTERACTIVE,stroke:KhanColors.INTERACTIVE})})},this.setupPic=(i,config)=>{const graphie=this.graphie;return this.setupTiledPlot(i,0,config,(x,y)=>{const scaledCenter=graphie.scalePoint([x,y]);const size=this.props.picSize;return graphie.raphael.image(this.props.picUrl,scaledCenter[0]-size/2,scaledCenter[1]-size/2,size,size)})},this.setupTiledPlot=(i,bottomMargin,config,createImage)=>{const self=this;const c=config;const graphie=self.graphie;const pics=graphie.pics;const dotTicks=graphie.dotTicks;const x=i+.5+c.picPad;graphie.mouselayer.canvas.style.touchAction="none";pics[i]=[];dotTicks[i]=[];const n=Math.round(c.dimY/c.scaleY)+1;___default.default(n).times(function(j){j-=1;const midY=(j+.5)*c.scaleY;const leftX=x-c.picBoxWidth/2;const topY=midY+.5*c.scaleY;const coord=graphie.scalePoint([leftX,topY+bottomMargin]);const mouseRect=graphie.mouselayer.rect(coord[0],coord[1],c.picBoxWidthPx,c.picBoxHeight);$__default.default(mouseRect[0]).css({fill:"#000",opacity:0,cursor:"pointer"}).on("vmousedown",function(e){e.preventDefault();self.whichPicClicked=i;self.setPicHeight(i,topY);$__default.default(document).on("vmouseup.plotTile",function(e){$__default.default(document).unbind(".plotTile");});$__default.default(document).on("vmousemove.plotTile",function(e){e.preventDefault();const yCoord=graphie.getMouseCoord(e)[1];const adjustedCoord=Math.floor(yCoord-bottomMargin);const newJ=Math.max(-1,Math.floor(adjustedCoord/c.scaleY));const newMidY=(newJ+.5)*c.scaleY;const newTopY=Math.min(newMidY+.5*c.scaleY,c.dimY);self.setPicHeight(self.whichPicClicked,newTopY);});});if(j<0){return}pics[i][j]=createImage(x,midY+bottomMargin);dotTicks[i][j]=graphie.ellipse([x,midY+bottomMargin],[self.DOT_TICK_POINT_SIZE()/graphie.scale[0],self.DOT_TICK_POINT_SIZE()/graphie.scale[1]],{fill:"#dee1e3",stroke:"#dee1e3"});});return x},this.setPicHeight=(i,y)=>{const values=[...this.props.userInput];values[i]=y;this.drawPicHeights(values,this.props.userInput);this.changeAndTrack(values);},this.changeAndTrack=userInput=>{this.props.handleUserInput(userInput);this.props.trackInteraction();};}}Plotter.contextType=PerseusI18nContext;Plotter.defaultProps={type:"bar",labels:["",""],categories:[""],scaleY:1,maxY:10,snapsPerLine:2,picSize:40,picBoxHeight:48,picUrl:"",plotDimensions:[380,300],labelInterval:1};function getStartUserInput$2(options){return options.starting}function getCorrectUserInput(options){return options.correct}function getUserInputFromSerializedState$2(serializedState){return serializedState.values}var Plotter$1 = {name:"plotter",displayName:"Plotter",hidden:true,widget:Plotter,getCorrectUserInput,getStartUserInput: getStartUserInput$2,getUserInputFromSerializedState: getUserInputFromSerializedState$2};
|
|
2104
2106
|
|
|
2105
2107
|
const getPromptJSON$2=()=>{return getUnsupportedPromptJSON("python-program")};
|
|
2106
2108
|
|
|
@@ -2122,7 +2124,7 @@ var extraWidgets = [CSProgram$1,Categorizer$1,Definition$1,DeprecatedStandin$1,D
|
|
|
2122
2124
|
|
|
2123
2125
|
const init=function(){registerWidgets(basicWidgets);registerWidgets(extraWidgets);replaceDeprecatedWidgets();};
|
|
2124
2126
|
|
|
2125
|
-
const libName="@khanacademy/perseus";const libVersion="66.
|
|
2127
|
+
const libName="@khanacademy/perseus";const libVersion="66.4.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
2126
2128
|
|
|
2127
2129
|
const apiVersion={major:12,minor:0};
|
|
2128
2130
|
|
|
@@ -2158,7 +2160,7 @@ ${items.join("\n")}
|
|
|
2158
2160
|
| --- | --- |`;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}
|
|
2159
2161
|
${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 wonderStuffCore.keys(widgets).filter(id=>isWidgetIdInContent(perseusItem,id))};
|
|
2160
2162
|
|
|
2161
|
-
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}}}
|
|
2163
|
+
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"},showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true}}}}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}}}
|
|
2162
2164
|
|
|
2163
2165
|
const widgetNameToEnum={categorizer:"CATEGORIZER","cs-program":"CS_PROGRAM",definition:"DEFINITION","deprecated-standin":"DEPRECATED_STANDIN",dropdown:"DROPDOWN",explanation:"EXPLANATION",expression:"EXPRESSION","free-response":"FREE_RESPONSE","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}
|
|
2164
2166
|
|
|
@@ -2216,6 +2218,7 @@ exports.Renderer = Renderer;
|
|
|
2216
2218
|
exports.ScoringUtil = ScoringUtil;
|
|
2217
2219
|
exports.ServerItemRenderer = serverItemRenderer;
|
|
2218
2220
|
exports.TableWidget = Table$1;
|
|
2221
|
+
exports.UserInputManager = UserInputManager;
|
|
2219
2222
|
exports.Util = Util;
|
|
2220
2223
|
exports.Widgets = widgets$1;
|
|
2221
2224
|
exports.apiVersion = apiVersion;
|