@khanacademy/perseus-editor 28.8.0 → 28.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { addLibraryVersionToPerseusDebug } from '@khanacademy/perseus-utils';
2
2
  import * as React from 'react';
3
3
  import React__default, { useState, useId, createElement, useRef, useEffect } from 'react';
4
- import { PerseusMarkdown, Util, Widgets, excludeDenylistKeys, ApiOptions, preprocessTex, Log, components, Dependencies, iconTrash, ClassNames, usePerseusI18n, UserInputManager, Renderer, Categorizer as Categorizer$1, Changeable, EditorJsonify, Expression, interactiveSizes, GrapherWidget, GrapherUtil, containerSizeClass, getInteractiveBoxFromSizeClass, iconChevronDown, KhanColors, mathOnlyParser, getAngleCoords, getPolygonCoords, getPointCoords, getQuadraticCoords, getSinusoidCoords, getCircleCoords, getLinearSystemCoords, getSegmentCoords, getLineCoords, InteractiveGraphWidget, bodyXsmallBold, MatrixWidget, PlotterWidget, TableWidget, widgets } from '@khanacademy/perseus';
4
+ import { PerseusMarkdown, Util, Widgets, excludeDenylistKeys, ApiOptions, Log, preprocessTex, components, Dependencies, iconTrash, ClassNames, usePerseusI18n, UserInputManager, Renderer, Categorizer as Categorizer$1, Changeable, EditorJsonify, Expression, interactiveSizes, GrapherWidget, GrapherUtil, containerSizeClass, getInteractiveBoxFromSizeClass, iconChevronDown, KhanColors, mathOnlyParser, getAngleCoords, getPolygonCoords, getPointCoords, getQuadraticCoords, getSinusoidCoords, getCircleCoords, getLinearSystemCoords, getSegmentCoords, getLineCoords, InteractiveGraphWidget, bodyXsmallBold, MatrixWidget, PlotterWidget, TableWidget, widgets } from '@khanacademy/perseus';
5
5
  export { widgets } from '@khanacademy/perseus';
6
6
  import { generateImageWidget, generateImageOptions, isFeatureOn, CoreWidgetRegistry, applyDefaultsToWidget, PerseusError, Errors, ItemExtras, categorizerLogic, csProgramLogic, definitionLogic, dropdownLogic, explanationLogic, expressionLogic, deriveExtraKeys, PerseusExpressionAnswerFormConsidered, freeResponseLogic, gradedGroupLogic, gradedGroupSetLogic, grapherLogic, GrapherUtil as GrapherUtil$1, groupLogic, iframeLogic, imageLogic, inputNumberLogic, interactionLogic, lockedFigureColors, lockedFigureFillStyles, interactiveGraphLogic, labelImageLogic, matcherLogic, matrixLogic, getMatrixSize, measurerLogic, numberLineLogic, numericInputLogic, ordererLogic, passageLogic, passageRefLogic, passageRefTargetLogic, phetSimulationLogic, makeSafeUrl, plotterLogic, plotterPlotTypes, pythonProgramLogic, radioLogic, deriveNumCorrect, sorterLogic, tableLogic, videoLogic } from '@khanacademy/perseus-core';
7
7
  import * as PerseusLinter from '@khanacademy/perseus-linter';
@@ -22,9 +22,9 @@ import { StyleSheet, css } from 'aphrodite';
22
22
  import caretRight from '@phosphor-icons/core/bold/caret-right-bold.svg';
23
23
  import IconButton from '@khanacademy/wonder-blocks-icon-button';
24
24
  import $ from 'jquery';
25
- import katex from 'katex';
26
25
  import { Strut, Spring } from '@khanacademy/wonder-blocks-layout';
27
26
  import Switch from '@khanacademy/wonder-blocks-switch';
27
+ import katex from 'katex';
28
28
  import PropTypes from 'prop-types';
29
29
  import classNames from 'classnames';
30
30
  import { Checkbox as Checkbox$1, TextField, LabeledTextField, TextArea } from '@khanacademy/wonder-blocks-form';
@@ -63,7 +63,7 @@ import xIcon from '@phosphor-icons/core/regular/x.svg';
63
63
  import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
64
64
  import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
65
65
 
66
- const libName="@khanacademy/perseus-editor";const libVersion="28.8.0";addLibraryVersionToPerseusDebug(libName,libVersion);
66
+ const libName="@khanacademy/perseus-editor";const libVersion="28.8.2";addLibraryVersionToPerseusDebug(libName,libVersion);
67
67
 
68
68
  var jsxRuntime = {exports: {}};
69
69
 
@@ -1417,23 +1417,19 @@ const IMAGE_MARKDOWN_REGEX=/!\[[^\]]*\]\([^)]+\)/g;function getFirstAvailableWid
1417
1417
 
1418
1418
  const defaultItemEditorContext={question:{content:"",widgets:{},images:{}},onEditorChange:()=>{}};const ItemEditorContext=React.createContext(defaultItemEditorContext);function useItemEditorContext(){return React.useContext(ItemEditorContext)}
1419
1419
 
1420
- const IssueCta=({issue})=>{const{question,onEditorChange}=useItemEditorContext();const cta=getCtaForIssueId(issue.id,question,onEditorChange);if(!cta){return null}return jsxRuntimeExports.jsx(Button,{size:"small",onClick:cta.onClick,style:styles$V.button,children:cta.label},issue.id)};const styles$V={button:{marginTop:sizing.size_080,marginBottom:sizing.size_080}};
1420
+ const IssueCta=({issue})=>{const{question,onEditorChange}=useItemEditorContext();const cta=getCtaForIssueId(issue.id,question,onEditorChange);if(!cta){return null}return jsxRuntimeExports.jsx(Button,{size:"small",onClick:cta.onClick,style:styles$U.button,children:cta.label},issue.id)};const styles$U={button:{marginTop:sizing.size_080,marginBottom:sizing.size_080}};
1421
1421
 
1422
- const PerseusEditorAccordion=props=>{const{animated,children,header,expanded,containerStyle,panelStyle,headerStyle,onToggle}=props;return jsxRuntimeExports.jsx(View,{className:"perseus-editor-accordion",children:jsxRuntimeExports.jsx(AccordionSection,{animated:animated,expanded:expanded,onToggle:onToggle,style:[styles$U.container,containerStyle],headerStyle:[styles$U.accordionHeader,headerStyle],header:header,children:jsxRuntimeExports.jsx(View,{style:[styles$U.accordionPanel,panelStyle],children:children})})})};const styles$U=StyleSheet.create({container:{backgroundColor:semanticColor.core.background.instructive.subtle,marginTop:spacing.xSmall_8},accordionHeader:{padding:spacing.small_12,paddingInlineEnd:0,height:spacing.xxLarge_48},accordionPanel:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxxSmall_4,paddingLeft:spacing.small_12,paddingRight:spacing.small_12}});
1422
+ const PerseusEditorAccordion=props=>{const{animated,children,header,expanded,containerStyle,panelStyle,headerStyle,onToggle}=props;return jsxRuntimeExports.jsx(View,{className:"perseus-editor-accordion",children:jsxRuntimeExports.jsx(AccordionSection,{animated:animated,expanded:expanded,onToggle:onToggle,style:[styles$T.container,containerStyle],headerStyle:[styles$T.accordionHeader,headerStyle],header:header,children:jsxRuntimeExports.jsx(View,{style:[styles$T.accordionPanel,panelStyle],children:children})})})};const styles$T=StyleSheet.create({container:{backgroundColor:semanticColor.core.background.instructive.subtle,marginTop:spacing.xSmall_8},accordionHeader:{padding:spacing.small_12,paddingInlineEnd:0,height:spacing.xxLarge_48},accordionPanel:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxxSmall_4,paddingLeft:spacing.small_12,paddingRight:spacing.small_12}});
1423
1423
 
1424
1424
  const impactStringMap={high:"Error",medium:"Warning",low:"Guideline"};const IssueDetails=({apiOptions,issue})=>{const[expanded,setExpanded]=React.useState(false);const toggleVisibility=()=>setExpanded(!expanded);const imageUpgradeFF=isFeatureOn({apiOptions},"image-widget-upgrade");return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{animated:true,expanded:expanded,onToggle:toggleVisibility,containerStyle:{backgroundColor:issue.impact==="high"?semanticColor.feedback.critical.subtle.background:semanticColor.feedback.warning.subtle.background},panelStyle:{backgroundColor:"white"},header:jsxRuntimeExports.jsx(LabelLarge,{style:{textOverflow:"ellipsis",maxWidth:"100%",overflow:"hidden",whiteSpace:"nowrap"},children:`${impactStringMap[issue.impact]}: ${issue.id}`}),children:[jsxRuntimeExports.jsx(LabelSmall,{style:{fontWeight:"bold"},children:"Description:"}),jsxRuntimeExports.jsx("span",{children:issue.description}),jsxRuntimeExports.jsx("a",{href:issue.helpUrl,target:"_blank",rel:"noreferrer",children:issue.help}),jsxRuntimeExports.jsx(LabelSmall,{style:{marginTop:"1em",fontWeight:"bold"},children:"Impact:"}),jsxRuntimeExports.jsxs("span",{style:{fontWeight:"initial"},children:[" ",issue.impact]}),jsxRuntimeExports.jsx(LabelSmall,{style:{marginTop:"1em",fontWeight:"bold"},children:"Issue:"}),jsxRuntimeExports.jsx("span",{style:{whiteSpace:"pre-line",color:semanticColor.core.foreground.critical.subtle},children:issue.message}),imageUpgradeFF&&jsxRuntimeExports.jsx(IssueCta,{issue:issue})]})};
1425
1425
 
1426
- function ToggleableCaret(props){const iconStyle=props.isExpanded?styles$T.expanded:styles$T.collapsed;return jsxRuntimeExports.jsx(PhosphorIcon,{icon:caretRight,style:iconStyle})}const styles$T=StyleSheet.create({collapsed:{transition:".15s"},expanded:{transform:"rotate(90deg)",transition:".15s"}});
1426
+ function ToggleableCaret(props){const iconStyle=props.isExpanded?styles$S.expanded:styles$S.collapsed;return jsxRuntimeExports.jsx(PhosphorIcon,{icon:caretRight,style:iconStyle})}const styles$S=StyleSheet.create({collapsed:{transition:".15s"},expanded:{transform:"rotate(90deg)",transition:".15s"}});
1427
1427
 
1428
1428
  const IssuesPanel=({apiOptions,issues=[]})=>{const[showPanel,setShowPanel]=useState(false);const hasWarnings=issues.length>0;const issuesCount=`${issues.length} issue${issues.length===1?"":"s"}`;const icon=hasWarnings?iconWarning:iconPass;const iconColor=hasWarnings?color.gold:color.green;return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor-title",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-title-id",children:jsxRuntimeExports.jsxs(View,{style:{display:"flex",flexDirection:"row",alignItems:"center",gap:"0.25em"},onClick:()=>setShowPanel(!showPanel),children:[jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:showPanel}),jsxRuntimeExports.jsx("span",{children:"Issues"})]})}),jsxRuntimeExports.jsx(PhosphorIcon,{icon:icon,size:"medium",color:iconColor,testId:`issues-icon-${icon}`,style:{marginRight:"0.25em"}}),issuesCount]}),showPanel&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-editor-panel",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-editor-content",children:[issues.map(issue=>jsxRuntimeExports.jsx(IssueDetails,{apiOptions:apiOptions,issue:issue},issue.id)),issues.length===0&&jsxRuntimeExports.jsx("div",{children:"No issues found"})]})})]})};
1429
1429
 
1430
1430
  class JsonEditor extends React.Component{getInitialState(){return {currentValue:JSON.stringify(this.props.value,null,4),valid:true}}UNSAFE_componentWillReceiveProps(nextProps){const shouldReplaceContent=!this.state.valid||!_.isEqual(nextProps.value,JSON.parse(this.state.currentValue?this.state.currentValue:""));if(shouldReplaceContent){this.setState(this.getInitialState());}}handleKeyDown(e){if(e.key==="Tab"){const cursorPos=e.target.selectionStart;const v=e.target.value;const textBefore=v.substring(0,cursorPos);const textAfter=v.substring(cursorPos,v.length);e.target.value=textBefore+" "+textAfter;e.target.selectionStart=textBefore.length+4;e.target.selectionEnd=textBefore.length+4;e.preventDefault();this.handleChange(e);}}handleChange(e){const nextString=e.target.value;try{let json=JSON.parse(nextString);if(_.isString(json)){json=JSON.parse(json);}this.setState({currentValue:nextString,valid:true},function(){this.props.onChange(json);});}catch{this.setState({currentValue:nextString,valid:false});}}handleBlur(e){const nextString=e.target.value;try{let json=JSON.parse(nextString);if(_.isString(json)){json=JSON.parse(json);}this.setState({currentValue:JSON.stringify(json,null,4),valid:true},function(){this.props.onChange(json);});}catch{this.setState({currentValue:JSON.stringify(this.props.value,null,4),valid:true});}}render(){const classes="perseus-json-editor "+(this.state.valid?"valid":"invalid");return jsxRuntimeExports.jsx("textarea",{className:classes,value:this.state.currentValue,onChange:this.handleChange,onKeyDown:this.handleKeyDown,onBlur:this.handleBlur,disabled:this.props.editingDisabled})}constructor(props){super(props);this.state=this.getInitialState();this.handleBlur=this.handleBlur.bind(this);this.handleChange=this.handleChange.bind(this);this.handleKeyDown=this.handleKeyDown.bind(this);}}JsonEditor.defaultProps={value:{}};
1431
1431
 
1432
- const SectionControlButton=({icon,onClick,title,disabled})=>{return jsxRuntimeExports.jsx(IconButton,{icon:icon,disabled:disabled,"aria-label":title,style:styles$S.button,size:"xsmall",onClick:onClick})};const styles$S=StyleSheet.create({button:{marginLeft:5}});
1433
-
1434
- const chemParse=function(tokens,stateMachine){let str="";let expectedLoc=tokens[tokens.length-1].loc.start;for(let i=tokens.length-1;i>=0;i--){if(tokens[i].loc.start>expectedLoc){str+=" ";expectedLoc=tokens[i].loc.start;}str+=tokens[i].text;expectedLoc+=tokens[i].text.length;}const tex=texify.go(mhchemParser.go(str,stateMachine));return tex};var mhchemParser={go:function(input,stateMachine){if(!input){return []}if(stateMachine===undefined){stateMachine="ce";}let state="0";const buffer={};buffer["parenthesisLevel"]=0;input=input.replace(/\n/g," ");input=input.replace(/[\u2212\u2013\u2014\u2010]/g,"-");input=input.replace(/[\u2026]/g,"...");let lastInput;let watchdog=10;const output=[];while(true){if(lastInput!==input){watchdog=10;lastInput=input;}else {watchdog--;}const machine=mhchemParser.stateMachines[stateMachine];const t=machine.transitions[state]||machine.transitions["*"];iterateTransitions:for(let i=0;i<t.length;i++){const matches=mhchemParser.patterns.match_(t[i].pattern,input);if(matches){const task=t[i].task;for(let iA=0;iA<task.action_.length;iA++){var o;if(machine.actions[task.action_[iA].type_]){o=machine.actions[task.action_[iA].type_](buffer,matches.match_,task.action_[iA].option);}else if(mhchemParser.actions[task.action_[iA].type_]){o=mhchemParser.actions[task.action_[iA].type_](buffer,matches.match_,task.action_[iA].option);}else {throw ["MhchemBugA","mhchem bug A. Please report. ("+task.action_[iA].type_+")"]}mhchemParser.concatArray(output,o);}state=task.nextState||state;if(input.length>0){if(!task.revisit){input=matches.remainder;}if(!task.toContinue){break iterateTransitions}}else {return output}}}if(watchdog<=0){throw ["MhchemBugU","mhchem bug U. Please report."]}}},concatArray:function(a,b){if(b){if(Array.isArray(b)){for(let iB=0;iB<b.length;iB++){a.push(b[iB]);}}else {a.push(b);}}},patterns:{patterns:{empty:/^$/,else:/^./,else2:/^./,space:/^\s/,"space A":/^\s(?=[A-Z\\$])/,space$:/^\s$/,"a-z":/^[a-z]/,x:/^x/,x$:/^x$/,i$:/^i$/,letters:/^(?:[a-zA-Z\u03B1-\u03C9\u0391-\u03A9?@]|(?:\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))))+/,"\\greek":/^\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))/,"one lowercase latin letter $":/^(?:([a-z])(?:$|[^a-zA-Z]))$/,"$one lowercase latin letter$ $":/^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/,"one lowercase greek letter $":/^(?:\$?[\u03B1-\u03C9]\$?|\$?\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\s*\$?)(?:\s+|\{\}|(?![a-zA-Z]))$/,digits:/^[0-9]+/,"-9.,9":/^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/,"-9.,9 no missing 0":/^[+\-]?[0-9]+(?:[.,][0-9]+)?/,"(-)(9.,9)(e)(99)":function(input){const m=input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))?(\((?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))\))?(?:([eE]|\s*(\*|x|\\times|\u00D7)\s*10\^)([+\-]?[0-9]+|\{[+\-]?[0-9]+\}))?/);if(m&&m[0]){return {match_:m.splice(1),remainder:input.substr(m[0].length)}}return null},"(-)(9)^(-9)":function(input){const m=input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/);if(m&&m[0]){return {match_:m.splice(1),remainder:input.substr(m[0].length)}}return null},"state of aggregation $":function(input){const a=mhchemParser.patterns.findObserveGroups(input,"",/^\([a-z]{1,3}(?=[\),])/,")","");if(a&&a.remainder.match(/^($|[\s,;\)\]\}])/)){return a}const m=input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/);if(m){return {match_:m[0],remainder:input.substr(m[0].length)}}return null},"_{(state of aggregation)}$":/^_\{(\([a-z]{1,3}\))\}/,"{[(":/^(?:\\\{|\[|\()/,")]}":/^(?:\)|\]|\\\})/,", ":/^[,;]\s*/,",":/^[,;]/,".":/^[.]/,". ":/^([.\u22C5\u00B7\u2022])\s*/,"...":/^\.\.\.(?=$|[^.])/,"* ":/^([*])\s*/,"^{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^{","","","}")},"^($...$)":function(input){return mhchemParser.patterns.findObserveGroups(input,"^","$","$","")},"^a":/^\^([0-9]+|[^\\_])/,"^\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"^\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^",/^\\[a-zA-Z]+\{/,"}","")},"^\\x":/^\^(\\[a-zA-Z]+)\s*/,"^(-1)":/^\^(-?\d+)/,"'":/^'/,"_{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_{","","","}")},"_($...$)":function(input){return mhchemParser.patterns.findObserveGroups(input,"_","$","$","")},_9:/^_([+\-]?[0-9]+|[^\\])/,"_\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"_\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_",/^\\[a-zA-Z]+\{/,"}","")},"_\\x":/^_(\\[a-zA-Z]+)\s*/,"^_":/^(?:\^(?=_)|\_(?=\^)|[\^_]$)/,"{}":/^\{\}/,"{...}":function(input){return mhchemParser.patterns.findObserveGroups(input,"","{","}","")},"{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"{","","","}")},"$...$":function(input){return mhchemParser.patterns.findObserveGroups(input,"","$","$","")},"${(...)}$":function(input){return mhchemParser.patterns.findObserveGroups(input,"${","","","}$")},"$(...)$":function(input){return mhchemParser.patterns.findObserveGroups(input,"$","","","$")},"=<>":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(input){return mhchemParser.patterns.findObserveGroups(input,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}0":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color{","","","}")},"\\color{(...)}{(...)}1":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color{","","","}","{","","","}")},"\\color(...){(...)}2":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\ce{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(input){let match;match=input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}const a=mhchemParser.patterns.findObserveGroups(input,"","$","$","");if(a){match=a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}}return null},amount2:function(input){return this["amount"](input)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(input){if(input.match(/^\([a-z]+\)$/)){return null}const match=input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}return null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(input,begExcl,begIncl,endIncl,endExcl,beg2Excl,beg2Incl,end2Incl,end2Excl,combine){const _match=function(input,pattern){if(typeof pattern==="string"){if(input.indexOf(pattern)!==0){return null}return pattern}const match=input.match(pattern);if(!match){return null}return match[0]};const _findObserveGroups=function(input,i,endChars){let braces=0;while(i<input.length){const a=input.charAt(i);const match=_match(input.substr(i),endChars);if(match!==null&&braces===0){return {endMatchBegin:i,endMatchEnd:i+match.length}}if(a==="{"){braces++;}else if(a==="}"){if(braces===0){throw ["ExtraCloseMissingOpen","Extra close brace or missing open brace"]}else {braces--;}}i++;}if(braces>0){return null}return null};let match=_match(input,begExcl);if(match===null){return null}input=input.substr(match.length);match=_match(input,begIncl);if(match===null){return null}const e=_findObserveGroups(input,match.length,endIncl||endExcl);if(e===null){return null}const match1=input.substring(0,endIncl?e.endMatchEnd:e.endMatchBegin);if(!(beg2Excl||beg2Incl)){return {match_:match1,remainder:input.substr(e.endMatchEnd)}}const group2=this.findObserveGroups(input.substr(e.endMatchEnd),beg2Excl,beg2Incl,end2Incl,end2Excl);if(group2===null){return null}const matchRet=[match1,group2.match_];return {match_:combine?matchRet.join(""):matchRet,remainder:group2.remainder}},match_:function(m,input){const pattern=mhchemParser.patterns.patterns[m];if(pattern===undefined){throw ["MhchemBugP","mhchem bug P. Please report. ("+m+")"]}else if(typeof pattern==="function"){return mhchemParser.patterns.patterns[m](input)}else {const match=input.match(pattern);if(match){let mm;if(match[2]){mm=[match[1],match[2]];}else if(match[1]){mm=match[1];}else {mm=match[0];}return {match_:mm,remainder:input.substr(match[0].length)}}return null}}},actions:{"a=":function(buffer,m){buffer.a=(buffer.a||"")+m;},"b=":function(buffer,m){buffer.b=(buffer.b||"")+m;},"p=":function(buffer,m){buffer.p=(buffer.p||"")+m;},"o=":function(buffer,m){buffer.o=(buffer.o||"")+m;},"q=":function(buffer,m){buffer.q=(buffer.q||"")+m;},"d=":function(buffer,m){buffer.d=(buffer.d||"")+m;},"rm=":function(buffer,m){buffer.rm=(buffer.rm||"")+m;},"text=":function(buffer,m){buffer.text_=(buffer.text_||"")+m;},insert:function(buffer,m,a){return {type_:a}},"insert+p1":function(buffer,m,a){return {type_:a,p1:m}},"insert+p1+p2":function(buffer,m,a){return {type_:a,p1:m[0],p2:m[1]}},copy:function(buffer,m){return m},rm:function(buffer,m){return {type_:"rm",p1:m||""}},text:function(buffer,m){return mhchemParser.go(m,"text")},"{text}":function(buffer,m){const ret=["{"];mhchemParser.concatArray(ret,mhchemParser.go(m,"text"));ret.push("}");return ret},"tex-math":function(buffer,m){return mhchemParser.go(m,"tex-math")},"tex-math tight":function(buffer,m){return mhchemParser.go(m,"tex-math tight")},bond:function(buffer,m,k){return {type_:"bond",kind_:k||m}},"color0-output":function(buffer,m){return {type_:"color0",color:m[0]}},ce:function(buffer,m){return mhchemParser.go(m)},"1/2":function(buffer,m){const ret=[];if(m.match(/^[+\-]/)){ret.push(m.substr(0,1));m=m.substr(1);}const n=m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/);n[1]=n[1].replace(/\$/g,"");ret.push({type_:"frac",p1:n[1],p2:n[2]});if(n[3]){n[3]=n[3].replace(/\$/g,"");ret.push({type_:"tex-math",p1:n[3]});}return ret},"9,9":function(buffer,m){return mhchemParser.go(m,"9,9")}},createTransitions:function(o){let pattern;let state;let stateArray;let i;const transitions={};for(pattern in o){for(state in o[pattern]){stateArray=state.split("|");o[pattern][state].stateArray=stateArray;for(i=0;i<stateArray.length;i++){transitions[stateArray[i]]=[];}}}for(pattern in o){for(state in o[pattern]){stateArray=o[pattern][state].stateArray||[];for(i=0;i<stateArray.length;i++){const p=o[pattern][state];if(p.action_){p.action_=[].concat(p.action_);for(let k=0;k<p.action_.length;k++){if(typeof p.action_[k]==="string"){p.action_[k]={type_:p.action_[k]};}}}else {p.action_=[];}const patternArray=pattern.split("|");for(let j=0;j<patternArray.length;j++){if(stateArray[i]==="*"){for(const t in transitions){transitions[t].push({pattern:patternArray[j],task:p});}}else {transitions[stateArray[i]].push({pattern:patternArray[j],task:p});}}}}}return transitions},stateMachines:{}};mhchemParser.stateMachines={ce:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},else:{"0|1|2":{action_:"beginsWithBond=false",revisit:true,toContinue:true}},oxidation$:{0:{action_:"oxidation-output"}},CMT:{r:{action_:"rdt=",nextState:"rt"},rd:{action_:"rqt=",nextState:"rdt"}},arrowUpDown:{"0|1|2|as":{action_:["sb=false","output","operator"],nextState:"1"}},uprightEntities:{"0|1|2":{action_:["o=","output"],nextState:"1"}},orbital:{"0|1|2|3":{action_:"o=",nextState:"o"}},"->":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:false},nextState:"2"},q:{action_:{type_:"- after o/d",option:false},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:true},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{}},space:{a:{nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". |* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}0":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:true},as:{action_:["output","sb=true"],nextState:"1",revisit:true},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:true},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(buffer,m){let ret;if((buffer.d||"").match(/^[0-9]+$/)){const tmp=buffer.d;buffer.d=undefined;ret=this["output"](buffer);buffer.b=tmp;}else {ret=this["output"](buffer);}mhchemParser.actions["o="](buffer,m);return ret},"d= kv":function(buffer,m){buffer.d=m;buffer.dType="kv";},"charge or bond":function(buffer,m){if(buffer["beginsWithBond"]){const ret=[];mhchemParser.concatArray(ret,this["output"](buffer));mhchemParser.concatArray(ret,mhchemParser.actions["bond"](buffer,m,"-"));return ret}buffer.d=m;},"- after o/d":function(buffer,m,isAfterD){let c1=mhchemParser.patterns.match_("orbital",buffer.o||"");const c2=mhchemParser.patterns.match_("one lowercase greek letter $",buffer.o||"");const c3=mhchemParser.patterns.match_("one lowercase latin letter $",buffer.o||"");const c4=mhchemParser.patterns.match_("$one lowercase latin letter$ $",buffer.o||"");const hyphenFollows=m==="-"&&(c1&&c1.remainder===""||c2||c3||c4);if(hyphenFollows&&!buffer.a&&!buffer.b&&!buffer.p&&!buffer.d&&!buffer.q&&!c1&&c3){buffer.o="$"+buffer.o+"$";}const ret=[];if(hyphenFollows){mhchemParser.concatArray(ret,this["output"](buffer));ret.push({type_:"hyphen"});}else {c1=mhchemParser.patterns.match_("digits",buffer.d||"");if(isAfterD&&c1&&c1.remainder===""){mhchemParser.concatArray(ret,mhchemParser.actions["d="](buffer,m));mhchemParser.concatArray(ret,this["output"](buffer));}else {mhchemParser.concatArray(ret,this["output"](buffer));mhchemParser.concatArray(ret,mhchemParser.actions["bond"](buffer,m,"-"));}}return ret},"a to o":function(buffer){buffer.o=buffer.a;buffer.a=undefined;},"sb=true":function(buffer){buffer.sb=true;},"sb=false":function(buffer){buffer.sb=false;},"beginsWithBond=true":function(buffer){buffer["beginsWithBond"]=true;},"beginsWithBond=false":function(buffer){buffer["beginsWithBond"]=false;},"parenthesisLevel++":function(buffer){buffer["parenthesisLevel"]++;},"parenthesisLevel--":function(buffer){buffer["parenthesisLevel"]--;},"state of aggregation":function(buffer,m){return {type_:"state of aggregation",p1:mhchemParser.go(m,"o")}},comma:function(buffer,m){const a=m.replace(/\s*$/,"");const withSpace=a!==m;if(withSpace&&buffer["parenthesisLevel"]===0){return {type_:"comma enumeration L",p1:a}}return {type_:"comma enumeration M",p1:a}},output:function(buffer,m,entityFollows){let ret;if(!buffer.r){ret=[];if(!buffer.a&&!buffer.b&&!buffer.p&&!buffer.o&&!buffer.q&&!buffer.d&&!entityFollows);else {if(buffer.sb){ret.push({type_:"entitySkip"});}if(!buffer.o&&!buffer.q&&!buffer.d&&!buffer.b&&!buffer.p&&entityFollows!==2){buffer.o=buffer.a;buffer.a=undefined;}else if(!buffer.o&&!buffer.q&&!buffer.d&&(buffer.b||buffer.p)){buffer.o=buffer.a;buffer.d=buffer.b;buffer.q=buffer.p;buffer.a=buffer.b=buffer.p=undefined;}else {if(buffer.o&&buffer.dType==="kv"&&mhchemParser.patterns.match_("d-oxidation$",buffer.d||"")){buffer.dType="oxidation";}else if(buffer.o&&buffer.dType==="kv"&&!buffer.q){buffer.dType=undefined;}}ret.push({type_:"chemfive",a:mhchemParser.go(buffer.a,"a"),b:mhchemParser.go(buffer.b,"bd"),p:mhchemParser.go(buffer.p,"pq"),o:mhchemParser.go(buffer.o,"o"),q:mhchemParser.go(buffer.q,"pq"),d:mhchemParser.go(buffer.d,buffer.dType==="oxidation"?"oxidation":"bd"),dType:buffer.dType});}}else {let rd;if(buffer.rdt==="M"){rd=mhchemParser.go(buffer.rd,"tex-math");}else if(buffer.rdt==="T"){rd=[{type_:"text",p1:buffer.rd||""}];}else {rd=mhchemParser.go(buffer.rd);}let rq;if(buffer.rqt==="M"){rq=mhchemParser.go(buffer.rq,"tex-math");}else if(buffer.rqt==="T"){rq=[{type_:"text",p1:buffer.rq||""}];}else {rq=mhchemParser.go(buffer.rq);}ret={type_:"arrow",r:buffer.r,rd:rd,rq:rq};}for(const p in buffer){if(p!=="parenthesisLevel"&&p!=="beginsWithBond"){delete buffer[p];}}return ret},"oxidation-output":function(buffer,m){const ret=["{"];mhchemParser.concatArray(ret,mhchemParser.go(m,"oxidation"));ret.push("}");return ret},"frac-output":function(buffer,m){return {type_:"frac-ce",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"overset-output":function(buffer,m){return {type_:"overset",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"underset-output":function(buffer,m){return {type_:"underset",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"underbrace-output":function(buffer,m){return {type_:"underbrace",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1])}},"r=":function(buffer,m){buffer.r=m;},"rdt=":function(buffer,m){buffer.rdt=m;},"rd=":function(buffer,m){buffer.rd=m;},"rqt=":function(buffer,m){buffer.rqt=m;},"rq=":function(buffer,m){buffer.rq=m;},operator:function(buffer,m,p1){return {type_:"operator",kind_:p1||m}}}},a:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:true}},"$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:true}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"{text}"}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(buffer){if(buffer.text_){const ret={type_:"text",p1:buffer.text_};for(const p in buffer){delete buffer[p];}return ret}}}},pq:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{nextState:"!f",revisit:true}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{nextState:"f",revisit:true}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"!f",revisit:true}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(buffer,m){return {type_:"state of aggregation subscript",p1:mhchemParser.go(m,"o")}},"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1],"pq")}}}},bd:{transitions:mhchemParser.createTransitions({empty:{"*":{}},x$:{0:{nextState:"!f",revisit:true}},formula$:{0:{nextState:"f",revisit:true}},else:{0:{nextState:"!f",revisit:true}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1],"bd")}}}},oxidation:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(buffer,m){return {type_:"roman numeral",p1:m||""}}}},"tex-math":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(buffer){if(buffer.o){const ret={type_:"tex-math",p1:buffer.o};for(const p in buffer){delete buffer[p];}return ret}}}},"tex-math tight":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(buffer,m){buffer.o=(buffer.o||"")+"{"+m+"}";},output:function(buffer){if(buffer.o){const ret={type_:"tex-math",p1:buffer.o};for(const p in buffer){delete buffer[p];}return ret}}}},"9,9":{transitions:mhchemParser.createTransitions({empty:{"*":{}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return {type_:"commaDecimal"}}}},pu:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(buffer,m){const ret=[];if(m[0]==="+-"||m[0]==="+/-"){ret.push("\\pm ");}else if(m[0]){ret.push(m[0]);}if(m[1]){mhchemParser.concatArray(ret,mhchemParser.go(m[1],"pu-9,9"));if(m[2]){if(m[2].match(/[,.]/)){mhchemParser.concatArray(ret,mhchemParser.go(m[2],"pu-9,9"));}else {ret.push(m[2]);}}m[3]=m[4]||m[3];if(m[3]){m[3]=m[3].trim();if(m[3]==="e"||m[3].substr(0,1)==="*"){ret.push({type_:"cdot"});}else {ret.push({type_:"times"});}}}if(m[3]){ret.push("10^{"+m[5]+"}");}return ret},"number^":function(buffer,m){const ret=[];if(m[0]==="+-"||m[0]==="+/-"){ret.push("\\pm ");}else if(m[0]){ret.push(m[0]);}mhchemParser.concatArray(ret,mhchemParser.go(m[1],"pu-9,9"));ret.push("^{"+m[2]+"}");return ret},operator:function(buffer,m,p1){return {type_:"operator",kind_:p1||m}},space:function(){return {type_:"pu-space-1"}},output:function(buffer){let ret;const md=mhchemParser.patterns.match_("{(...)}",buffer.d||"");if(md&&md.remainder===""){buffer.d=md.match_;}const mq=mhchemParser.patterns.match_("{(...)}",buffer.q||"");if(mq&&mq.remainder===""){buffer.q=mq.match_;}if(buffer.d){buffer.d=buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C");buffer.d=buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");}if(buffer.q){buffer.q=buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C");buffer.q=buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");const b5={d:mhchemParser.go(buffer.d,"pu"),q:mhchemParser.go(buffer.q,"pu")};if(buffer.o==="//"){ret={type_:"pu-frac",p1:b5.d,p2:b5.q};}else {ret=b5.d;if(b5.d.length>1||b5.q.length>1){ret.push({type_:" / "});}else {ret.push({type_:"/"});}mhchemParser.concatArray(ret,b5.q);}}else {ret=mhchemParser.go(buffer.d,"pu-2");}for(const p in buffer){delete buffer[p];}return ret}}},"pu-2":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return {type_:"tight cdot"}},"^(-1)":function(buffer,m){buffer.rm+="^{"+m+"}";},space:function(){return {type_:"pu-space-2"}},output:function(buffer){let ret=[];if(buffer.rm){const mrm=mhchemParser.patterns.match_("{(...)}",buffer.rm||"");if(mrm&&mrm.remainder===""){ret=mhchemParser.go(mrm.match_,"pu");}else {ret={type_:"rm",p1:buffer.rm};}}for(const p in buffer){delete buffer[p];}return ret}}},"pu-9,9":{transitions:mhchemParser.createTransitions({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return {type_:"commaDecimal"}},"output-0":function(buffer){const ret=[];buffer.text_=buffer.text_||"";if(buffer.text_.length>4){let a=buffer.text_.length%3;if(a===0){a=3;}for(let i=buffer.text_.length-3;i>0;i-=3){ret.push(buffer.text_.substr(i,3));ret.push({type_:"1000 separator"});}ret.push(buffer.text_.substr(0,a));ret.reverse();}else {ret.push(buffer.text_);}for(const p in buffer){delete buffer[p];}return ret},"output-o":function(buffer){const ret=[];buffer.text_=buffer.text_||"";if(buffer.text_.length>4){const a=buffer.text_.length-3;for(var i=0;i<a;i+=3){ret.push(buffer.text_.substr(i,3));ret.push({type_:"1000 separator"});}ret.push(buffer.text_.substr(i));}else {ret.push(buffer.text_);}for(const p in buffer){delete buffer[p];}return ret}}}};var texify={go:function(input,isInner){if(!input){return ""}let res="";let cee=false;for(let i=0;i<input.length;i++){const inputi=input[i];if(typeof inputi==="string"){res+=inputi;}else {res+=texify._go2(inputi);if(inputi.type_==="1st-level escape"){cee=true;}}}if(!isInner&&!cee&&res){res="{"+res+"}";}return res},_goInner:function(input){if(!input){return input}return texify.go(input,true)},_go2:function(buf){let res;switch(buf.type_){case "chemfive":res="";var b5={a:texify._goInner(buf.a),b:texify._goInner(buf.b),p:texify._goInner(buf.p),o:texify._goInner(buf.o),q:texify._goInner(buf.q),d:texify._goInner(buf.d)};if(b5.a){if(b5.a.match(/^[+\-]/)){b5.a="{"+b5.a+"}";}res+=b5.a+"\\,";}if(b5.b||b5.p){res+="{\\vphantom{X}}";res+="^{\\hphantom{"+(b5.b||"")+"}}_{\\hphantom{"+(b5.p||"")+"}}";res+="{\\vphantom{X}}";res+="^{\\smash[t]{\\vphantom{2}}\\mathllap{"+(b5.b||"")+"}}";res+="_{\\vphantom{2}\\mathllap{\\smash[t]{"+(b5.p||"")+"}}}";}if(b5.o){if(b5.o.match(/^[+\-]/)){b5.o="{"+b5.o+"}";}res+=b5.o;}if(buf.dType==="kv"){if(b5.d||b5.q){res+="{\\vphantom{X}}";}if(b5.d){res+="^{"+b5.d+"}";}if(b5.q){res+="_{\\smash[t]{"+b5.q+"}}";}}else if(buf.dType==="oxidation"){if(b5.d){res+="{\\vphantom{X}}";res+="^{"+b5.d+"}";}if(b5.q){res+="{\\vphantom{X}}";res+="_{\\smash[t]{"+b5.q+"}}";}}else {if(b5.q){res+="{\\vphantom{X}}";res+="_{\\smash[t]{"+b5.q+"}}";}if(b5.d){res+="{\\vphantom{X}}";res+="^{"+b5.d+"}";}}break;case "rm":res="\\mathrm{"+buf.p1+"}";break;case "text":if(buf.p1.match(/[\^_]/)){buf.p1=buf.p1.replace(" ","~").replace("-","\\text{-}");res="\\mathrm{"+buf.p1+"}";}else {res="\\text{"+buf.p1+"}";}break;case "roman numeral":res="\\mathrm{"+buf.p1+"}";break;case "state of aggregation":res="\\mskip2mu "+texify._goInner(buf.p1);break;case "state of aggregation subscript":res="\\mskip1mu "+texify._goInner(buf.p1);break;case "bond":res=texify._getBond(buf.kind_);if(!res){throw ["MhchemErrorBond","mhchem Error. Unknown bond type ("+buf.kind_+")"]}break;case "frac":var c="\\frac{"+buf.p1+"}{"+buf.p2+"}";res="\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}";break;case "pu-frac":var d="\\frac{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";res="\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}";break;case "tex-math":res=buf.p1+" ";break;case "frac-ce":res="\\frac{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "overset":res="\\overset{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "underset":res="\\underset{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "underbrace":res="\\underbrace{"+texify._goInner(buf.p1)+"}_{"+texify._goInner(buf.p2)+"}";break;case "color":res="{\\color{"+buf.color1+"}{"+texify._goInner(buf.color2)+"}}";break;case "color0":res="\\color{"+buf.color+"}";break;case "arrow":var b6={rd:texify._goInner(buf.rd),rq:texify._goInner(buf.rq)};var arrow="\\x"+texify._getArrow(buf.r);if(b6.rq){arrow+="[{"+b6.rq+"}]";}if(b6.rd){arrow+="{"+b6.rd+"}";}else {arrow+="{}";}res=arrow;break;case "operator":res=texify._getOperator(buf.kind_);break;case "1st-level escape":res=buf.p1+" ";break;case "space":res=" ";break;case "entitySkip":res="~";break;case "pu-space-1":res="~";break;case "pu-space-2":res="\\mkern3mu ";break;case "1000 separator":res="\\mkern2mu ";break;case "commaDecimal":res="{,}";break;case "comma enumeration L":res="{"+buf.p1+"}\\mkern6mu ";break;case "comma enumeration M":res="{"+buf.p1+"}\\mkern3mu ";break;case "comma enumeration S":res="{"+buf.p1+"}\\mkern1mu ";break;case "hyphen":res="\\text{-}";break;case "addition compound":res="\\,{\\cdot}\\,";break;case "electron dot":res="\\mkern1mu \\bullet\\mkern1mu ";break;case "KV x":res="{\\times}";break;case "prime":res="\\prime ";break;case "cdot":res="\\cdot ";break;case "tight cdot":res="\\mkern1mu{\\cdot}\\mkern1mu ";break;case "times":res="\\times ";break;case "circa":res="{\\sim}";break;case "^":res="uparrow";break;case "v":res="downarrow";break;case "ellipsis":res="\\ldots ";break;case "/":res="/";break;case " / ":res="\\,/\\,";break;default:throw ["MhchemBugT","mhchem bug T. Please report."]}return res},_getArrow:function(a){switch(a){case "->":return "rightarrow";case "→":return "rightarrow";case "⟶":return "rightarrow";case "<-":return "leftarrow";case "<->":return "leftrightarrow";case "<-->":return "rightleftarrows";case "<=>":return "rightleftharpoons";case "⇌":return "rightleftharpoons";case "<=>>":return "rightequilibrium";case "<<=>":return "leftequilibrium";default:throw ["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(a){switch(a){case "-":return "{-}";case "1":return "{-}";case "=":return "{=}";case "2":return "{=}";case "#":return "{\\equiv}";case "3":return "{\\equiv}";case "~":return "{\\tripledash}";case "~-":return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}";case "~=":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case "~--":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case "-~-":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}";case "...":return "{{\\cdot}{\\cdot}{\\cdot}}";case "....":return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case "->":return "{\\rightarrow}";case "<-":return "{\\leftarrow}";case "<":return "{<}";case ">":return "{>}";default:throw ["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(a){switch(a){case "+":return " {}+{} ";case "-":return " {}-{} ";case "=":return " {}={} ";case "<":return " {}<{} ";case ">":return " {}>{} ";case "<<":return " {}\\ll{} ";case ">>":return " {}\\gg{} ";case "\\pm":return " {}\\pm{} ";case "\\approx":return " {}\\approx{} ";case "$\\approx$":return " {}\\approx{} ";case "v":return " \\downarrow{} ";case "(v)":return " \\downarrow{} ";case "^":return " \\uparrow{} ";case "(^)":return " \\uparrow{} ";default:throw ["MhchemBugT","mhchem bug T. Please report."]}}};
1435
-
1436
- katex.__defineMacro("\\ce",function(context){return chemParse(context.consumeArgs(1)[0],"ce")});katex.__defineMacro("\\pu",function(context){return chemParse(context.consumeArgs(1)[0],"pu")});katex.__defineMacro("\\tripledash","{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu"+"\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}");
1432
+ const SectionControlButton=({icon,onClick,title,disabled})=>{return jsxRuntimeExports.jsx(IconButton,{icon:icon,disabled:disabled,"aria-label":title,style:styles$R.button,size:"xsmall",onClick:onClick})};const styles$R=StyleSheet.create({button:{marginLeft:5}});
1437
1433
 
1438
1434
  class DragTarget extends React.Component{handleDrop(e){e.stopPropagation();e.preventDefault();this.setState({dragHover:false});this.props.onDrop(e);}handleDragEnd(){this.setState({dragHover:false});}handleDragOver(e){e.preventDefault();}handleDragLeave(){this.setState({dragHover:false});}handleDragEnter(e){this.setState({dragHover:this.props.shouldDragHighlight(e)});}render(){const opacity=this.state.dragHover?{opacity:.3}:{};const{component:Component,shouldDragHighlight,...forwardProps}=this.props;return jsxRuntimeExports.jsx(Component,{...forwardProps,style:Object.assign({},this.props.style,opacity),onDrop:this.handleDrop,onDragEnd:this.handleDragEnd,onDragOver:this.handleDragOver,onDragEnter:this.handleDragEnter,onDragLeave:this.handleDragLeave})}constructor(props){super(props);this.state={dragHover:false};this.handleDrop=this.handleDrop.bind(this);this.handleDragEnd=this.handleDragEnd.bind(this);this.handleDragOver=this.handleDragOver.bind(this);this.handleDragLeave=this.handleDragLeave.bind(this);this.handleDragEnter=this.handleDragEnter.bind(this);}}DragTarget.defaultProps={component:"div",shouldDragHighlight:()=>true};
1439
1435
 
@@ -1441,15 +1437,21 @@ const _upgradeWidgetInfo=props=>{const filteredProps=excludeDenylistKeys(props);
1441
1437
 
1442
1438
  class WidgetSelect extends React.Component{shouldComponentUpdate(){return false}render(){const widgets=Widgets.getPublicWidgets();const orderedWidgetNames=_.sortBy(_.keys(widgets),name=>{return widgets[name].displayName});const addWidgetString="Add a widget…";return jsxRuntimeExports.jsxs("select",{value:"",onChange:this.handleChange,"data-testid":"editor__widget-select",children:[jsxRuntimeExports.jsx("option",{value:"",children:addWidgetString}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),orderedWidgetNames.map(name=>{return jsxRuntimeExports.jsx("option",{value:name,children:widgets[name].displayName},name)})]})}constructor(...args){super(...args),this.handleChange=e=>{const widgetType=e.currentTarget.value;if(widgetType===""){return}if(this.props.onChange){this.props.onChange(widgetType);}};}}
1443
1439
 
1444
- class TexErrorView extends React.Component{render(){const{errorList}=this.props;const{showErrors}=this.state;return jsxRuntimeExports.jsxs(View,{style:styles$R.errorContainer,children:[jsxRuntimeExports.jsxs(View,{style:styles$R.title,onClick:this.handleToggleTexErrors,children:[jsxRuntimeExports.jsx(ToggleableCaret,{isExpanded:showErrors}),"  TeX Errors (",errorList.length,")"]}),showErrors&&jsxRuntimeExports.jsx(View,{style:styles$R.errorExplanation,children:"If your math doesn't display correctly, these errors might help you troubleshoot. Message #content-kitchen for help."}),showErrors&&errorList.map((e,index)=>jsxRuntimeExports.jsxs(View,{style:styles$R.error,children:[jsxRuntimeExports.jsx(View,{style:{color:"red"},children:e.math}),jsxRuntimeExports.jsx(View,{children:e.message})]},index))]})}constructor(...args){super(...args),this.state={showErrors:false},this.handleToggleTexErrors=e=>{this.setState({showErrors:!this.state.showErrors});};}}const styles$R=StyleSheet.create({title:{backgroundColor:"#eee",fontSize:"1.25em",padding:"4px 10px",cursor:"pointer",display:"flex",flexDirection:"row",alignItems:"center"},errorContainer:{border:"1px solid #ddd",borderTop:"none"},errorExplanation:{padding:"4px 10px",backgroundColor:"pink"},error:{padding:"4px 10px"}});
1445
-
1446
- const widgetPlaceholder="[[☃ {id}]]";const widgetRegExp="(\\[\\[☃ {id}\\]\\])";const rWidgetSplit=new RegExp(widgetRegExp.replace("{id}","[a-z-]+ [0-9]+"),"g");const shortcutRegexp=/^\[\[([a-z-]+)$/;const ENDS_WITH_A_PARAGRAPH=/(?:\n{2,}|^\n*)$/;const TRAILING_NEWLINES=/(\n*)$/;const LEADING_NEWLINES=/^(\n*)/;const commafyInteger=n=>{let str=n.toString();if(str.length>=5){str=str.replace(/(\d)(?=(\d{3})+$)/g,"$1{,}");}return str};const makeEndWithAParagraphIfNecessary=content=>{if(!ENDS_WITH_A_PARAGRAPH.test(content)){const match=TRAILING_NEWLINES.exec(content);if(match){const newlines=match[1];return content+"\n\n".slice(0,2-newlines.length)}}return content};const makeStartWithAParagraphAlways=content=>{const match=LEADING_NEWLINES.exec(content);if(!match){return content}const newlines=match[1];return "\n\n".slice(0,2-newlines.length)+content};const IMAGE_REGEX$1=/!\[[^\]]*\]\(([^\s)]+)[^)]*\)/g;const allMatches=function(regex,str){const result=[];while(true){const match=regex.exec(str);if(!match){break}result.push(match);}return result};const imageUrlsFromContent=function(content){return allMatches(IMAGE_REGEX$1,content).map(capture=>capture[1])};class Editor extends React.Component{componentDidMount(){this.lastUserValue=null;this._sizeImages(this.props);$(this.textarea.current).on("copy cut",this._maybeCopyWidgets).on("paste",this._maybePasteWidgets);}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.content!==nextProps.content){this.setState({textAreaValue:nextProps.content});}}componentDidUpdate(prevProps){const textarea=this.textarea.current;if(this.lastUserValue!=null&&textarea){textarea.focus();textarea.value=this.lastUserValue;textarea.selectionStart=0;textarea.setSelectionRange(0,prevProps.content.length);if(document.execCommand("insertText",false,this.props.content)===false){textarea.value=this.props.content;}this.lastUserValue=null;}if(this.props.content!==prevProps.content){this._sizeImages(this.props);}}getWidgetEditor(id,type){if(!Widgets.getEditor(type)){return}return createElement(WidgetEditor,{...this.props.widgets[id],ref:id,id:id,key:id,onChange:this._handleWidgetEditorChange.bind(this,id),onRemove:this._handleWidgetEditorRemove.bind(this,id),apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}render(){let pieces;let widgets;let underlayPieces;let widgetsDropDown;let templatesDropDown;let widgetsAndTemplates;let wordCountDisplay;const katexErrorList=[];if(this.props.showWordCount){const numChars=PerseusMarkdown.characterCount(this.props.content);const numWords=Math.floor(numChars/6);wordCountDisplay=jsxRuntimeExports.jsx("span",{className:"perseus-editor-word-count",title:"~"+commafyInteger(numWords)+" words ("+commafyInteger(numChars)+" characters)",children:commafyInteger(numWords)});}if(this.props.widgetEnabled){pieces=this.props.content.split(rWidgetSplit);widgets={};underlayPieces=[];for(let i=0;i<pieces.length;i++){if(i%2===0){underlayPieces.push(pieces[i]);const ast=PerseusMarkdown.parse(pieces[i]);PerseusMarkdown.traverseContent(ast,node=>{if(node.type==="math"||node.type==="blockMath"){const content=preprocessTex(node.content);try{katex.renderToString(content,{colorIsTextColor:true});}catch(e){katexErrorList.push({math:content,message:e.message});}}});}else {const match=Util.rWidgetParts.exec(pieces[i]);if(match!=null){const id=match[1];const type=match[2];const duplicate=id in widgets;widgets[id]=this.getWidgetEditor(id,type);const classes=(duplicate||!widgets[id]?"error ":"")+("");const key=duplicate?i:id;underlayPieces.push(jsxRuntimeExports.jsx("b",{className:classes,children:pieces[i]},key));}}}this.widgetIds=_.keys(widgets);widgetsDropDown=jsxRuntimeExports.jsx(WidgetSelect,{onChange:this._addWidget});const insertTemplateString="Insert template…";templatesDropDown=jsxRuntimeExports.jsxs("select",{onChange:this.addTemplate,"data-testid":"editor__template-select",children:[jsxRuntimeExports.jsx("option",{value:"",children:insertTemplateString}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"table",children:"Table"}),jsxRuntimeExports.jsx("option",{value:"titledTable",children:"Titled table"}),jsxRuntimeExports.jsx("option",{value:"alignment",children:"Aligned equations"}),jsxRuntimeExports.jsx("option",{value:"piecewise",children:"Piecewise function"}),Object.keys(this.props.additionalTemplates).length>0&&jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),Object.entries(this.props.additionalTemplates).map(([key])=>jsxRuntimeExports.jsx("option",{value:key,children:key},key)),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"allWidgets",children:"All widgets (for testing)"})]});if(!this.props.immutableWidgets){const widgetNodes=Object.values(widgets);widgetsAndTemplates=jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets-selectors",children:[widgetsDropDown,templatesDropDown,wordCountDisplay]}),widgetNodes]});wordCountDisplay=null;}}else {underlayPieces=[this.props.content];}underlayPieces.push(jsxRuntimeExports.jsx("br",{},"end"));const completeTextarea=[jsxRuntimeExports.jsx("div",{className:"perseus-textarea-underlay",ref:this.underlay,children:underlayPieces},"underlay"),jsxRuntimeExports.jsx("textarea",{ref:this.textarea,onChange:this.handleChange,onKeyDown:this._handleKeyDown,placeholder:this.props.placeholder,disabled:this.props.disabled,value:this.state.textAreaValue},"textarea")];let textareaWrapper;if(this.props.imageUploader){textareaWrapper=jsxRuntimeExports.jsx(DragTarget,{onDrop:this.handleDrop,className:"perseus-textarea-pair",children:completeTextarea});}else {textareaWrapper=jsxRuntimeExports.jsx("div",{className:"perseus-textarea-pair",children:completeTextarea});}const contentWithoutWidgets=this.props.content.replace(/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g,"");const noPrompt=contentWithoutWidgets.trim().length===0;const noWidgets=!/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g.test(this.props.content);const warningStyle={borderTop:"none",padding:4,backgroundColor:"pink"};const editingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{"data-testid":"perseus-single-editor",className:"perseus-single-editor "+(this.props.className||"")+(editingDisabled?" perseus-editor-disabled":""),children:[textareaWrapper,katexErrorList.length>0&&jsxRuntimeExports.jsx(TexErrorView,{errorList:katexErrorList}),this.props.warnNoPrompt&&noPrompt&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain a prompt"}),this.props.warnNoWidgets&&noWidgets&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain at least one widget"}),wordCountDisplay,widgetsAndTemplates]})}constructor(...args){super(...args),this.underlay=React.createRef(),this.textarea=React.createRef(),this.state={textAreaValue:this.props.content},this._handleWidgetEditorChange=(id,newWidgetInfo,cb,silent)=>{const widgets=Object.assign({},this.props.widgets);widgets[id]=Object.assign({},widgets[id],newWidgetInfo);this.props.onChange({widgets},cb,silent);},this._handleWidgetEditorRemove=id=>{if(!confirm("Are you sure you want to delete this item?")){return}const textarea=this.textarea.current;const re=new RegExp(widgetRegExp.replace("{id}",id),"gm");this.props.onChange({content:textarea?.value.replace(re,"")});},this._sizeImages=props=>{const imageUrls=imageUrlsFromContent(props.content);const images=_.pick(props.images,imageUrls);const newImageUrls=_.filter(imageUrls,url=>!images[url]);_.each(newImageUrls,url=>{Util.getImageSize(url,(width,height)=>{images[url]={width:width,height:height};props.onChange({images:_.clone(images)},null,true);});});},this.handleDrop=e=>{const{imageUploader}=this.props;let content=this.state.textAreaValue||"";const dataTransfer=e.dataTransfer;if(!dataTransfer||!imageUploader){return}const files=dataTransfer.files;if(files.length===0){const imageUrl=dataTransfer.getData("URL");if(imageUrl){const newContent=content+"\n\n![]("+imageUrl+")";this.lastUserValue=this.props.content;this.props.onChange({content:newContent});}return}const origContent=this.state.textAreaValue;_(files).chain().map(function(file){if(!file.type.match("image.*")){return null}const sentinel="☃ "+_.uniqueId("image_");content+="\n\n![]("+sentinel+")";return {file:file,sentinel:sentinel}}).reject(_.isNull).tap(()=>{this.lastUserValue=origContent;this.props.onChange({content:content});}).each(fileAndSentinel=>{imageUploader(fileAndSentinel.file,url=>{this.lastUserValue=origContent;this.props.onChange({content:this.state.textAreaValue.replace(fileAndSentinel.sentinel,url)});});});},this.handleChange=e=>{const newValue=e.currentTarget.value;this.setState({textAreaValue:newValue});if(newValue!==this.props.content){this.props.onChange({content:newValue});}},this._handleKeyDown=e=>{e.stopPropagation();if(e.key==="Tab"){const textarea=this.textarea.current;const word=Util.textarea.getWordBeforeCursor(textarea);const matches=word.string.toLowerCase().match(shortcutRegexp);if(matches!=null){const text=matches[1];const widgets=Widgets.getAllWidgetTypes();const matchingWidgets=widgets.filter(name=>{return name.substring(0,text.length)===text});if(matchingWidgets.length===1){const widgetType=matchingWidgets[0];this._addWidgetToContent(this.props.content,[word.pos.start,word.pos.end+1],widgetType);}e.preventDefault();}}},this._maybeCopyWidgets=e=>{const textarea=e.currentTarget;const selectedText=textarea.value.substring(textarea.selectionStart,textarea.selectionEnd);const widgetNames=_.map(selectedText.match(rWidgetSplit),syntax=>{return Util.rWidgetParts.exec(syntax)[1]});const widgetData=_.pick(this.serialize().widgets,widgetNames);localStorage.perseusLastCopiedText=selectedText;localStorage.perseusLastCopiedWidgets=JSON.stringify(widgetData);Log.log(`Widgets copied: ${localStorage.perseusLastCopiedWidgets}`);},this._maybePasteWidgets=e=>{const widgetJSON=localStorage.perseusLastCopiedWidgets;const lastCopiedText=localStorage.perseusLastCopiedText;const textToBePasted=e.originalEvent.clipboardData.getData("text");if(widgetJSON&&lastCopiedText===textToBePasted){e.preventDefault();const widgetData=JSON.parse(widgetJSON);const safeWidgetMapping=this._safeWidgetNameMapping(widgetData);const safeWidgetData={};for(const[key,data]of Object.entries(widgetData)){safeWidgetData[safeWidgetMapping[key]]=data;}const newWidgets=_.extend(safeWidgetData,this.props.widgets);const safeText=lastCopiedText.replace(rWidgetSplit,syntax=>{const match=Util.rWidgetParts.exec(syntax);const completeWidget=match[0];const widget=match[1];return completeWidget.replace(widget,safeWidgetMapping[widget])});const textarea=e.currentTarget;const selectionStart=textarea.selectionStart;const newContent=this.state.textAreaValue.substr(0,selectionStart)+safeText+this.state.textAreaValue.substr(textarea.selectionEnd);this.lastUserValue=this.state.textAreaValue;this.props.onChange({content:newContent,widgets:newWidgets},()=>{const expectedCursorPosition=selectionStart+safeText.length;Util.textarea.moveCursor(textarea,expectedCursorPosition);});}},this._safeWidgetNameMapping=widgetData=>{const widgets=_.keys(widgetData).map(name=>name.split(" "));const widgetTypes=_.uniq(widgets.map(widget=>widget[0]));const existingWidgets=_.keys(this.props.widgets).map(name=>name.split(" "));const safeWidgetNums={};_.each(widgetTypes,type=>{safeWidgetNums[type]=_.chain(existingWidgets).filter(existingWidget=>existingWidget[0]===type).map(existingWidget=>+existingWidget[1]+1).max().value();safeWidgetNums[type]=Math.max(safeWidgetNums[type],1);});const safeWidgetMapping={};_.each(widgets,widget=>{const widgetName=widget.join(" ");const widgetType=widget[0];safeWidgetMapping[widgetName]=`${widgetType} ${safeWidgetNums[widgetType]}`;safeWidgetNums[widgetType]++;});return safeWidgetMapping},this._addWidgetToContent=(oldContent,cursorRange,widgetType)=>{const allWidgetIds=_.map(oldContent.match(rWidgetSplit),syntax=>{const match=Util.rWidgetParts.exec(syntax);const type=match[2];const num=+match[3];return [type,num]});const widgetNum=_.reduce(allWidgetIds,(currentNum,otherId)=>{const[otherType,otherNum]=otherId;if(otherType===widgetType){return Math.max(otherNum+1,currentNum)}return currentNum},1);const id=widgetType+" "+widgetNum;const widgetContent=widgetPlaceholder.replace("{id}",id);const isBlock=CoreWidgetRegistry.getDefaultAlignment(widgetType)==="block";const prelude=oldContent.slice(0,cursorRange[0]);const postlude=oldContent.slice(cursorRange[1]);const newPrelude=isBlock?makeEndWithAParagraphIfNecessary(prelude):prelude;const newPostlude=isBlock?makeStartWithAParagraphAlways(postlude):postlude;const newContent=newPrelude+widgetContent+newPostlude;const newWidgets={...this.props.widgets};newWidgets[id]={options:Widgets.getEditor(widgetType)?.defaultProps,type:widgetType,version:Widgets.getVersion(widgetType)};this.lastUserValue=this.props.content;this.props.onChange({content:newContent,widgets:newWidgets},()=>{if(!this.textarea.current){return}Util.textarea.moveCursor(this.textarea.current,newContent.length-postlude.length);});},this._addWidget=widgetType=>{const textarea=this.textarea.current;if(!textarea){return}this._addWidgetToContent(this.props.content,[textarea.selectionStart,textarea.selectionEnd],widgetType);textarea.focus();},this.addTemplate=e=>{const templateType=e.currentTarget.value;if(templateType===""){return}e.currentTarget.value="";let oldContent=this.props.content;oldContent=oldContent.replace(/\n*$/,"\n\n");let template;if(templateType==="table"){template="header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="titledTable"){template="|| **Table title** ||\n"+"header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="alignment"){template="$\\begin{align} \n"+"\\\\\\\\\n"+"\\end{align}$";}else if(templateType==="piecewise"){template="$f(x) = \\begin{cases}\n"+"7 & \\text{if }x=1 \\\\\n"+"f(x-1)+5 & \\text{if }x > 1\n"+"\\end{cases}$";}else if(templateType==="allWidgets"){template=Widgets.getAllWidgetTypes().map(type=>`[[${Util.snowman} ${type} 1]]`).join("\n\n");}else if(templateType in this.props.additionalTemplates){template=this.props.additionalTemplates[templateType];}else {throw new PerseusError("Invalid template type: "+templateType,Errors.InvalidInput,{metadata:{templateType}})}const newContent=oldContent+template;this.lastUserValue=this.props.content;this.props.onChange({content:newContent},this.focusAndMoveToEnd);},this.getSaveWarnings=()=>{const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));const warnings=_(widgetIds).chain().map(id=>{const issuesFunc=this.refs[id].getSaveWarnings;const issues=issuesFunc?issuesFunc():[];return _.map(issues,issue=>id+": "+issue)}).flatten(true).value();return warnings},this.focus=()=>{const textarea=this.textarea.current;if(textarea){textarea.focus();}},this.focusAndMoveToEnd=()=>{this.focus();const textarea=this.textarea.current;if(textarea){textarea.selectionStart=textarea.value.length;textarea.selectionEnd=textarea.value.length;}},this.serialize=options=>{const widgets={};const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));_.each(widgetIds,id=>{widgets[id]=this.refs[id].serialize();});if(options&&options.keepDeletedWidgets){_.chain(this.props.widgets).keys().reject(id=>_.contains(widgetIds,id)).each(id=>{widgets[id]=this.props.widgets[id];});}return {replace:this.props.replace,content:this.props.content,images:this.props.images,widgets:widgets}};}}Editor.defaultProps={content:"",placeholder:"",widgets:{},images:{},disabled:false,widgetEnabled:true,immutableWidgets:false,showWordCount:false,warnNoPrompt:false,warnNoWidgets:false,additionalTemplates:{},apiOptions:ApiOptions.defaults};
1440
+ const widgetPlaceholder="[[☃ {id}]]";const widgetRegExp="(\\[\\[☃ {id}\\]\\])";const rWidgetSplit=new RegExp(widgetRegExp.replace("{id}","[a-z-]+ [0-9]+"),"g");const shortcutRegexp=/^\[\[([a-z-]+)$/;const ENDS_WITH_A_PARAGRAPH=/(?:\n{2,}|^\n*)$/;const TRAILING_NEWLINES=/(\n*)$/;const LEADING_NEWLINES=/^(\n*)/;const commafyInteger=n=>{let str=n.toString();if(str.length>=5){str=str.replace(/(\d)(?=(\d{3})+$)/g,"$1{,}");}return str};const makeEndWithAParagraphIfNecessary=content=>{if(!ENDS_WITH_A_PARAGRAPH.test(content)){const match=TRAILING_NEWLINES.exec(content);if(match){const newlines=match[1];return content+"\n\n".slice(0,2-newlines.length)}}return content};const makeStartWithAParagraphAlways=content=>{const match=LEADING_NEWLINES.exec(content);if(!match){return content}const newlines=match[1];return "\n\n".slice(0,2-newlines.length)+content};const IMAGE_REGEX$1=/!\[[^\]]*\]\(([^\s)]+)[^)]*\)/g;const allMatches=function(regex,str){const result=[];while(true){const match=regex.exec(str);if(!match){break}result.push(match);}return result};const imageUrlsFromContent=function(content){return allMatches(IMAGE_REGEX$1,content).map(capture=>capture[1])};class Editor extends React.Component{componentDidMount(){this.lastUserValue=null;this._sizeImages(this.props);$(this.textarea.current).on("copy cut",this._maybeCopyWidgets).on("paste",this._maybePasteWidgets);}UNSAFE_componentWillReceiveProps(nextProps){if(this.props.content!==nextProps.content){this.setState({textAreaValue:nextProps.content});}}componentDidUpdate(prevProps){const textarea=this.textarea.current;if(this.lastUserValue!=null&&textarea){textarea.focus();textarea.value=this.lastUserValue;textarea.selectionStart=0;textarea.setSelectionRange(0,prevProps.content.length);if(document.execCommand("insertText",false,this.props.content)===false){textarea.value=this.props.content;}this.lastUserValue=null;}if(this.props.content!==prevProps.content){this._sizeImages(this.props);}}getWidgetEditor(id,type){if(!Widgets.getEditor(type)){return}return createElement(WidgetEditor,{...this.props.widgets[id],ref:id,id:id,key:id,onChange:this._handleWidgetEditorChange.bind(this,id),onRemove:this._handleWidgetEditorRemove.bind(this,id),apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}render(){let pieces;let widgets;let underlayPieces;let widgetsDropDown;let templatesDropDown;let widgetsAndTemplates;let wordCountDisplay;if(this.props.showWordCount){const numChars=PerseusMarkdown.characterCount(this.props.content);const numWords=Math.floor(numChars/6);wordCountDisplay=jsxRuntimeExports.jsx("span",{className:"perseus-editor-word-count",title:"~"+commafyInteger(numWords)+" words ("+commafyInteger(numChars)+" characters)",children:commafyInteger(numWords)});}if(this.props.widgetEnabled){pieces=this.props.content.split(rWidgetSplit);widgets={};underlayPieces=[];for(let i=0;i<pieces.length;i++){if(i%2===0){underlayPieces.push(pieces[i]);}else {const match=Util.rWidgetParts.exec(pieces[i]);if(match!=null){const id=match[1];const type=match[2];const duplicate=id in widgets;widgets[id]=this.getWidgetEditor(id,type);const classes=(duplicate||!widgets[id]?"error ":"")+("");const key=duplicate?i:id;underlayPieces.push(jsxRuntimeExports.jsx("b",{className:classes,children:pieces[i]},key));}}}this.widgetIds=_.keys(widgets);widgetsDropDown=jsxRuntimeExports.jsx(WidgetSelect,{onChange:this._addWidget});const insertTemplateString="Insert template…";templatesDropDown=jsxRuntimeExports.jsxs("select",{onChange:this.addTemplate,"data-testid":"editor__template-select",children:[jsxRuntimeExports.jsx("option",{value:"",children:insertTemplateString}),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"table",children:"Table"}),jsxRuntimeExports.jsx("option",{value:"titledTable",children:"Titled table"}),jsxRuntimeExports.jsx("option",{value:"alignment",children:"Aligned equations"}),jsxRuntimeExports.jsx("option",{value:"piecewise",children:"Piecewise function"}),Object.keys(this.props.additionalTemplates).length>0&&jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),Object.entries(this.props.additionalTemplates).map(([key])=>jsxRuntimeExports.jsx("option",{value:key,children:key},key)),jsxRuntimeExports.jsx("option",{disabled:true,children:"--"}),jsxRuntimeExports.jsx("option",{value:"allWidgets",children:"All widgets (for testing)"})]});if(!this.props.immutableWidgets){const widgetNodes=Object.values(widgets);widgetsAndTemplates=jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-widgets-selectors",children:[widgetsDropDown,templatesDropDown,wordCountDisplay]}),widgetNodes]});wordCountDisplay=null;}}else {underlayPieces=[this.props.content];}underlayPieces.push(jsxRuntimeExports.jsx("br",{},"end"));const completeTextarea=[jsxRuntimeExports.jsx("div",{className:"perseus-textarea-underlay",ref:this.underlay,children:underlayPieces},"underlay"),jsxRuntimeExports.jsx("textarea",{ref:this.textarea,onChange:this.handleChange,onKeyDown:this._handleKeyDown,placeholder:this.props.placeholder,disabled:this.props.disabled,value:this.state.textAreaValue},"textarea")];let textareaWrapper;if(this.props.imageUploader){textareaWrapper=jsxRuntimeExports.jsx(DragTarget,{onDrop:this.handleDrop,className:"perseus-textarea-pair",children:completeTextarea});}else {textareaWrapper=jsxRuntimeExports.jsx("div",{className:"perseus-textarea-pair",children:completeTextarea});}const contentWithoutWidgets=this.props.content.replace(/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g,"");const noPrompt=contentWithoutWidgets.trim().length===0;const noWidgets=!/\[\[\u2603 (([a-z-]+) ([0-9]+))\]\]/g.test(this.props.content);const warningStyle={borderTop:"none",padding:4,backgroundColor:"pink"};const editingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{"data-testid":"perseus-single-editor",className:"perseus-single-editor "+(this.props.className||"")+(editingDisabled?" perseus-editor-disabled":""),children:[textareaWrapper,this.props.warnNoPrompt&&noPrompt&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain a prompt"}),this.props.warnNoWidgets&&noWidgets&&jsxRuntimeExports.jsx("div",{style:warningStyle,children:"Graded Groups should contain at least one widget"}),wordCountDisplay,widgetsAndTemplates]})}constructor(...args){super(...args),this.underlay=React.createRef(),this.textarea=React.createRef(),this.state={textAreaValue:this.props.content},this._handleWidgetEditorChange=(id,newWidgetInfo,cb,silent)=>{const widgets=Object.assign({},this.props.widgets);widgets[id]=Object.assign({},widgets[id],newWidgetInfo);this.props.onChange({widgets},cb,silent);},this._handleWidgetEditorRemove=id=>{if(!confirm("Are you sure you want to delete this item?")){return}const textarea=this.textarea.current;const re=new RegExp(widgetRegExp.replace("{id}",id),"gm");this.props.onChange({content:textarea?.value.replace(re,"")});},this._sizeImages=props=>{const imageUrls=imageUrlsFromContent(props.content);const images=_.pick(props.images,imageUrls);const newImageUrls=_.filter(imageUrls,url=>!images[url]);_.each(newImageUrls,url=>{Util.getImageSize(url,(width,height)=>{images[url]={width:width,height:height};props.onChange({images:_.clone(images)},null,true);});});},this.handleDrop=e=>{const{imageUploader}=this.props;let content=this.state.textAreaValue||"";const dataTransfer=e.dataTransfer;if(!dataTransfer||!imageUploader){return}const files=dataTransfer.files;if(files.length===0){const imageUrl=dataTransfer.getData("URL");if(imageUrl){const newContent=content+"\n\n![]("+imageUrl+")";this.lastUserValue=this.props.content;this.props.onChange({content:newContent});}return}const origContent=this.state.textAreaValue;_(files).chain().map(function(file){if(!file.type.match("image.*")){return null}const sentinel="☃ "+_.uniqueId("image_");content+="\n\n![]("+sentinel+")";return {file:file,sentinel:sentinel}}).reject(_.isNull).tap(()=>{this.lastUserValue=origContent;this.props.onChange({content:content});}).each(fileAndSentinel=>{imageUploader(fileAndSentinel.file,url=>{this.lastUserValue=origContent;this.props.onChange({content:this.state.textAreaValue.replace(fileAndSentinel.sentinel,url)});});});},this.handleChange=e=>{const newValue=e.currentTarget.value;this.setState({textAreaValue:newValue});if(newValue!==this.props.content){this.props.onChange({content:newValue});}},this._handleKeyDown=e=>{e.stopPropagation();if(e.key==="Tab"){const textarea=this.textarea.current;const word=Util.textarea.getWordBeforeCursor(textarea);const matches=word.string.toLowerCase().match(shortcutRegexp);if(matches!=null){const text=matches[1];const widgets=Widgets.getAllWidgetTypes();const matchingWidgets=widgets.filter(name=>{return name.substring(0,text.length)===text});if(matchingWidgets.length===1){const widgetType=matchingWidgets[0];this._addWidgetToContent(this.props.content,[word.pos.start,word.pos.end+1],widgetType);}e.preventDefault();}}},this._maybeCopyWidgets=e=>{const textarea=e.currentTarget;const selectedText=textarea.value.substring(textarea.selectionStart,textarea.selectionEnd);const widgetNames=_.map(selectedText.match(rWidgetSplit),syntax=>{return Util.rWidgetParts.exec(syntax)[1]});const widgetData=_.pick(this.serialize().widgets,widgetNames);localStorage.perseusLastCopiedText=selectedText;localStorage.perseusLastCopiedWidgets=JSON.stringify(widgetData);Log.log(`Widgets copied: ${localStorage.perseusLastCopiedWidgets}`);},this._maybePasteWidgets=e=>{const widgetJSON=localStorage.perseusLastCopiedWidgets;const lastCopiedText=localStorage.perseusLastCopiedText;const textToBePasted=e.originalEvent.clipboardData.getData("text");if(widgetJSON&&lastCopiedText===textToBePasted){e.preventDefault();const widgetData=JSON.parse(widgetJSON);const safeWidgetMapping=this._safeWidgetNameMapping(widgetData);const safeWidgetData={};for(const[key,data]of Object.entries(widgetData)){safeWidgetData[safeWidgetMapping[key]]=data;}const newWidgets=_.extend(safeWidgetData,this.props.widgets);const safeText=lastCopiedText.replace(rWidgetSplit,syntax=>{const match=Util.rWidgetParts.exec(syntax);const completeWidget=match[0];const widget=match[1];return completeWidget.replace(widget,safeWidgetMapping[widget])});const textarea=e.currentTarget;const selectionStart=textarea.selectionStart;const newContent=this.state.textAreaValue.substr(0,selectionStart)+safeText+this.state.textAreaValue.substr(textarea.selectionEnd);this.lastUserValue=this.state.textAreaValue;this.props.onChange({content:newContent,widgets:newWidgets},()=>{const expectedCursorPosition=selectionStart+safeText.length;Util.textarea.moveCursor(textarea,expectedCursorPosition);});}},this._safeWidgetNameMapping=widgetData=>{const widgets=_.keys(widgetData).map(name=>name.split(" "));const widgetTypes=_.uniq(widgets.map(widget=>widget[0]));const existingWidgets=_.keys(this.props.widgets).map(name=>name.split(" "));const safeWidgetNums={};_.each(widgetTypes,type=>{safeWidgetNums[type]=_.chain(existingWidgets).filter(existingWidget=>existingWidget[0]===type).map(existingWidget=>+existingWidget[1]+1).max().value();safeWidgetNums[type]=Math.max(safeWidgetNums[type],1);});const safeWidgetMapping={};_.each(widgets,widget=>{const widgetName=widget.join(" ");const widgetType=widget[0];safeWidgetMapping[widgetName]=`${widgetType} ${safeWidgetNums[widgetType]}`;safeWidgetNums[widgetType]++;});return safeWidgetMapping},this._addWidgetToContent=(oldContent,cursorRange,widgetType)=>{const allWidgetIds=_.map(oldContent.match(rWidgetSplit),syntax=>{const match=Util.rWidgetParts.exec(syntax);const type=match[2];const num=+match[3];return [type,num]});const widgetNum=_.reduce(allWidgetIds,(currentNum,otherId)=>{const[otherType,otherNum]=otherId;if(otherType===widgetType){return Math.max(otherNum+1,currentNum)}return currentNum},1);const id=widgetType+" "+widgetNum;const widgetContent=widgetPlaceholder.replace("{id}",id);const isBlock=CoreWidgetRegistry.getDefaultAlignment(widgetType)==="block";const prelude=oldContent.slice(0,cursorRange[0]);const postlude=oldContent.slice(cursorRange[1]);const newPrelude=isBlock?makeEndWithAParagraphIfNecessary(prelude):prelude;const newPostlude=isBlock?makeStartWithAParagraphAlways(postlude):postlude;const newContent=newPrelude+widgetContent+newPostlude;const newWidgets={...this.props.widgets};newWidgets[id]={options:Widgets.getEditor(widgetType)?.defaultProps,type:widgetType,version:Widgets.getVersion(widgetType)};this.lastUserValue=this.props.content;this.props.onChange({content:newContent,widgets:newWidgets},()=>{if(!this.textarea.current){return}Util.textarea.moveCursor(this.textarea.current,newContent.length-postlude.length);});},this._addWidget=widgetType=>{const textarea=this.textarea.current;if(!textarea){return}this._addWidgetToContent(this.props.content,[textarea.selectionStart,textarea.selectionEnd],widgetType);textarea.focus();},this.addTemplate=e=>{const templateType=e.currentTarget.value;if(templateType===""){return}e.currentTarget.value="";let oldContent=this.props.content;oldContent=oldContent.replace(/\n*$/,"\n\n");let template;if(templateType==="table"){template="header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="titledTable"){template="|| **Table title** ||\n"+"header 1 | header 2 | header 3\n"+"- | - | -\n"+"data 1 | data 2 | data 3\n"+"data 4 | data 5 | data 6\n"+"data 7 | data 8 | data 9";}else if(templateType==="alignment"){template="$\\begin{align} \n"+"\\\\\\\\\n"+"\\end{align}$";}else if(templateType==="piecewise"){template="$f(x) = \\begin{cases}\n"+"7 & \\text{if }x=1 \\\\\n"+"f(x-1)+5 & \\text{if }x > 1\n"+"\\end{cases}$";}else if(templateType==="allWidgets"){template=Widgets.getAllWidgetTypes().map(type=>`[[${Util.snowman} ${type} 1]]`).join("\n\n");}else if(templateType in this.props.additionalTemplates){template=this.props.additionalTemplates[templateType];}else {throw new PerseusError("Invalid template type: "+templateType,Errors.InvalidInput,{metadata:{templateType}})}const newContent=oldContent+template;this.lastUserValue=this.props.content;this.props.onChange({content:newContent},this.focusAndMoveToEnd);},this.getSaveWarnings=()=>{const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));const warnings=_(widgetIds).chain().map(id=>{const issuesFunc=this.refs[id].getSaveWarnings;const issues=issuesFunc?issuesFunc():[];return _.map(issues,issue=>id+": "+issue)}).flatten(true).value();return warnings},this.focus=()=>{const textarea=this.textarea.current;if(textarea){textarea.focus();}},this.focusAndMoveToEnd=()=>{this.focus();const textarea=this.textarea.current;if(textarea){textarea.selectionStart=textarea.value.length;textarea.selectionEnd=textarea.value.length;}},this.serialize=options=>{const widgets={};const widgetIds=_.intersection(this.widgetIds,_.keys(this.refs));_.each(widgetIds,id=>{widgets[id]=this.refs[id].serialize();});if(options&&options.keepDeletedWidgets){_.chain(this.props.widgets).keys().reject(id=>_.contains(widgetIds,id)).each(id=>{widgets[id]=this.props.widgets[id];});}return {replace:this.props.replace,content:this.props.content,images:this.props.images,widgets:widgets}};}}Editor.defaultProps={content:"",placeholder:"",widgets:{},images:{},disabled:false,widgetEnabled:true,immutableWidgets:false,showWordCount:false,warnNoPrompt:false,warnNoWidgets:false,additionalTemplates:{},apiOptions:ApiOptions.defaults};
1447
1441
 
1448
1442
  let nextIframeID=0;const requestIframeData={};const updateIframeHeight={};window.iframeDataStore={};window.addEventListener("message",event=>{if(typeof event.data==="string"){const callback=requestIframeData[event.data];if(callback){callback();}}else if(event.data.id){if(event.data.height!==undefined){updateIframeHeight[event.data.id](event.data.height);}else if(event.data.lintWarnings){Log.log("LINTER REPORT",{lintWarnings:JSON.stringify(event.data.lintWarnings)});}}});class IframeContentRenderer extends React.Component{componentDidMount(){this._isMounted=true;this.iframeID=nextIframeID;nextIframeID++;this._prepareFrame();requestIframeData[this.iframeID]=()=>{this.sendNewData(this._lastData);};updateIframeHeight[this.iframeID]=height=>{this._lastHeight=height;if(this._isMounted&&this.props.seamless&&this.container.current){this.container.current.style.height=height+"px";}};}shouldComponentUpdate(nextProps){return nextProps.datasetValue!==this.props.datasetValue||nextProps.seamless!==this.props.seamless}componentDidUpdate(prevProps){if(this.container.current){if(!this.props.seamless){this.container.current.style.height="100%";}else {this.container.current.style.height=this._lastHeight+"px";}}if(prevProps.datasetValue!==this.props.datasetValue){this._prepareFrame();}}componentWillUnmount(){requestIframeData[this.iframeID]=null;updateIframeHeight[this.iframeID]=null;this._isMounted=false;}_prepareFrame(){if(this._frame){this.container.current?.removeChild(this._frame);}const frame=document.createElement("iframe");frame.style.width="100%";frame.style.height="100%";frame.src=this.props.url;if(this.props.datasetKey){frame.dataset[this.props.datasetKey]=this.props.datasetValue;}frame.dataset.id=String(this.iframeID);if(this.props.seamless){frame.dataset.lintGutter="true";}this.container.current?.appendChild(frame);this._frame=frame;}sendNewData(data){const frame=this._frame;if(this._isMounted&&data&&frame?.contentWindow){this._lastData=data;window.iframeDataStore[this.iframeID]=data;frame.contentWindow.postMessage(this.iframeID,"*");}}render(){return jsxRuntimeExports.jsx("div",{ref:this.container,style:{width:"100%",height:"100%"}})}constructor(...args){super(...args),this.container=React.createRef();}}
1449
1443
 
1450
- const SEVERITY_ERROR=1;const SEVERITY_WARNING=2;const SEVERITY_GUIDELINE=3;const SEVERITY_MAP={[SEVERITY_ERROR]:"high",[SEVERITY_WARNING]:"medium",[SEVERITY_GUIDELINE]:"low"};const WARNINGS={inaccessibleWidget:(widgetType,widgetId)=>({id:`${widgetId} inaccessible`,description:`This ${widgetType} widget (${widgetId}) is inaccessible. Consider using an alternative to support all learners. Please check out the following documentation on compliant widget options.`,helpUrl:"https://khanacademy.atlassian.net/wiki/spaces/LC/pages/1909489691/Widget+Fundamentals",help:"Widget Fundamentals",impact:"medium",message:"Selecting inaccessible widgets for a practice item will result in this exercise being hidden from users with 'Hide visually dependant content' setting set to true. Please select another widget or create an alternative practice item."}),genericLinterWarning:(rule,message,severity)=>({id:rule,description:message,help:"Learn more about best practices for authoring items",helpUrl:"https://docs.google.com/document/d/1N13f4sY-7EXWDwQ04ivA9vJBVvPPd60qjBT73B4NHuM/edit?tab=t.0",impact:SEVERITY_MAP[severity??SEVERITY_GUIDELINE],message:message})};
1444
+ const SEVERITY_ERROR=1;const SEVERITY_WARNING=2;const SEVERITY_GUIDELINE=3;const SEVERITY_MAP={[SEVERITY_ERROR]:"high",[SEVERITY_WARNING]:"medium",[SEVERITY_GUIDELINE]:"low"};const WARNINGS={inaccessibleWidget:(widgetType,widgetId)=>({id:`${widgetId} inaccessible`,description:`This ${widgetType} widget (${widgetId}) is inaccessible. Consider using an alternative to support all learners. Please check out the following documentation on compliant widget options.`,helpUrl:"https://khanacademy.atlassian.net/wiki/spaces/LC/pages/1909489691/Widget+Fundamentals",help:"Widget Fundamentals",impact:"medium",message:"Selecting inaccessible widgets for a practice item will result in this exercise being hidden from users with 'Hide visually dependant content' setting set to true. Please select another widget or create an alternative practice item."}),genericLinterWarning:(rule,message,severity)=>({id:rule,description:message,help:"Learn more about best practices for authoring items",helpUrl:"https://docs.google.com/document/d/1N13f4sY-7EXWDwQ04ivA9vJBVvPPd60qjBT73B4NHuM/edit?tab=t.0",impact:SEVERITY_MAP[severity??SEVERITY_GUIDELINE],message:message}),texError:(math,errorMessage,index)=>({id:`tex-debug-info-${index+1}`,description:"If your math doesn't display correctly, these errors might help you troubleshoot. Message #content-kitchen for help.",help:"Learn more about TeX syntax",helpUrl:"https://khan.github.io/KaTeX/",impact:"medium",message:`Error in: ${math}
1451
1445
 
1452
- const{HUD: HUD$1}=components;class ArticleEditor extends React.Component{componentDidMount(){this._updateIssues();this._updatePreviewFrames();}componentDidUpdate(prevProps){if(prevProps.json!==this.props.json||prevProps.issues!==this.props.issues){this._updateIssues();}this._updatePreviewFrames();}_updateIssues(){const sections=this.props.json instanceof Array?this.props.json:[this.props.json];const allLinterIssues=[];sections.forEach(section=>{const parsed=PerseusMarkdown.parse(section.content??"",{});const linterContext={content:section.content,widgets:section.widgets,stack:[]};const sectionIssues=PerseusLinter.runLinter(parsed,linterContext,false)?.map(linterWarning=>{if(linterWarning.rule==="inaccessible-widget"){return WARNINGS.inaccessibleWidget(linterWarning.metadata?.widgetType??"unknown",linterWarning.metadata?.widgetId??"unknown")}return WARNINGS.genericLinterWarning(linterWarning.rule,linterWarning.message,linterWarning.severity)})??[];allLinterIssues.push(...sectionIssues);});this.setState({issues:[...this.props.issues??[],...allLinterIssues]});}_updatePreviewFrames(){if(this.props.mode==="preview"){this.refs["frame-all"].sendNewData({type:"article-all",data:this._sections().map((section,i)=>{return this._apiOptionsForSection(section,i)})});}else if(this.props.mode==="edit"){this._sections().forEach((section,i)=>{this.refs["frame-"+i].sendNewData({type:"article",data:this._apiOptionsForSection(section,i)});});}}_apiOptionsForSection(section,sectionIndex){const editor=this.refs[`editor${sectionIndex}`];return {apiOptions:{...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true},json:section,useNewStyles:this.props.useNewStyles,linterContext:{contentType:"article",highlightLint:this.state.highlightLint,paths:this.props.contentPaths},legacyPerseusLint:editor?editor.getSaveWarnings():[]}}_sections(){const json=this.props.json;return json instanceof Array?json:[json]}_renderEditor(){const{imageUploader,sectionImageUploadGenerator}=this.props;const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true};const sections=this._sections();const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[sections.map((section,i)=>{return [jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsxs("fieldset",{disabled:editingDisabled,children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx(IssuesPanel,{apiOptions:this.props.apiOptions,issues:this.state.issues}),jsxRuntimeExports.jsxs("div",{className:"pod-title",children:["Section ",i+1,jsxRuntimeExports.jsxs("div",{style:{display:"inline-block",float:"right"},children:[sectionImageUploadGenerator(i),jsxRuntimeExports.jsx(SectionControlButton,{icon:plusIcon,disabled:editingDisabled,onClick:()=>{this._handleAddSectionAfter(i);},title:"Add a new section after this one"}),i+1<sections.length&&jsxRuntimeExports.jsx(SectionControlButton,{icon:arrowCircleDownIcon,disabled:editingDisabled,onClick:()=>{this._handleMoveSectionLater(i);},title:"Move this section down"}),i>0&&jsxRuntimeExports.jsx(SectionControlButton,{icon:arrowCircleUpIcon,disabled:editingDisabled,onClick:()=>{this._handleMoveSectionEarlier(i);},title:"Move this section up"}),jsxRuntimeExports.jsx(SectionControlButton,{icon:trashIcon,disabled:editingDisabled,onClick:()=>{const msg="Are you sure you "+"want to delete section "+(i+1)+"?";if(confirm(msg)){this._handleRemoveSection(i);}},title:"Delete this section"})]})]}),jsxRuntimeExports.jsx(Editor,{...section,apiOptions:apiOptions,imageUploader:imageUploader,onChange:newProps=>this._handleEditorChange(i,newProps),placeholder:"Type your section text here...",ref:"editor"+i})]}),jsxRuntimeExports.jsx("div",{className:"editor-preview",children:this._renderIframePreview(i,true)})]})},i)]}),this._renderAddSection(editingDisabled),this._renderLinterHUD()]})}_renderAddSection(editingDisabled){return jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,disabled:editingDisabled,kind:"tertiary","aria-label":"Add a section",onClick:()=>{this._handleAddSectionAfter(this._sections().length-1);},children:"Add a section"})})})}_renderLinterHUD(){return jsxRuntimeExports.jsx(HUD$1,{message:"Style warnings",enabled:this.state.highlightLint,onClick:()=>{this.setState({highlightLint:!this.state.highlightLint});}})}_renderIframePreview(i,nochrome){const isMobile=this.props.screen==="phone"||this.props.screen==="tablet";return jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.screen,nochrome:nochrome,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:"frame-"+i,datasetKey:"mobile",datasetValue:isMobile,seamless:nochrome,url:this.props.previewURL},this.props.screen)})}_renderPreviewMode(){return jsxRuntimeExports.jsx("div",{className:"standalone-preview",children:this._renderIframePreview("all",false)})}_handleMoveSectionEarlier(i){if(i===0){return}const sections=[...this._sections()];const section=sections[i];sections.splice(i,1);sections.splice(i-1,0,section);this.props.onChange({json:sections});}_handleMoveSectionLater(i){const sections=[...this._sections()];if(i+1===sections.length){return}const section=sections[i];sections.splice(i,1);sections.splice(i+1,0,section);this.props.onChange({json:sections});}_handleAddSectionAfter(i){const sections=_.clone(this.serialize());const newSection=i>=0?{widgets:sections[i].widgets}:{};sections.splice(i+1,0,newSection);this.props.onChange({json:sections});}_handleRemoveSection(i){const sections=[...this._sections()];sections.splice(i,1);this.props.onChange({json:sections});}serialize(){if(this.props.mode==="edit"){return this._sections().map((section,i)=>{return this.refs["editor"+i].serialize()})}if(this.props.mode==="preview"||this.props.mode==="json"){return this.props.json}throw new PerseusError("Could not serialize; mode "+this.props.mode+" not found",Errors.Internal)}getSaveWarnings(){if(this.props.mode!=="edit"){throw new PerseusError("Can only get save warnings in edit mode.",Errors.NotAllowed)}return this._sections().map((section,i)=>{return this.refs["editor"+i].getSaveWarnings()})}render(){const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsx(Dependencies.DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{className:"framework-perseus perseus-article-editor",children:[this.props.mode==="edit"&&this._renderEditor(),this.props.mode==="preview"&&this._renderPreviewMode(),this.props.mode==="json"&&jsxRuntimeExports.jsxs("div",{className:"json-editor",children:[jsxRuntimeExports.jsx("div",{className:"json-editor-warning",children:jsxRuntimeExports.jsx("span",{children:"Warning: Editing in this mode can lead to broken articles!"})}),jsxRuntimeExports.jsx(JsonEditor,{multiLine:true,onChange:this._handleJsonChange,value:this.props.json,editingDisabled:editingDisabled})]})]})})}constructor(...args){super(...args),this.state={highlightLint:true,issues:[]},this._handleJsonChange=newJson=>{this.props.onChange({json:newJson});},this._handleEditorChange=(i,newProps)=>{const sections=[...this._sections()];sections[i]={...sections[i],...newProps};this.props.onChange({json:sections});};}}ArticleEditor.defaultProps={contentPaths:[],json:[{}],mode:"edit",screen:"desktop",sectionImageUploadGenerator:()=>jsxRuntimeExports.jsx("span",{}),useNewStyles:false};
1446
+ ${errorMessage}`})};
1447
+
1448
+ const chemParse=function(tokens,stateMachine){let str="";let expectedLoc=tokens[tokens.length-1].loc.start;for(let i=tokens.length-1;i>=0;i--){if(tokens[i].loc.start>expectedLoc){str+=" ";expectedLoc=tokens[i].loc.start;}str+=tokens[i].text;expectedLoc+=tokens[i].text.length;}const tex=texify.go(mhchemParser.go(str,stateMachine));return tex};var mhchemParser={go:function(input,stateMachine){if(!input){return []}if(stateMachine===undefined){stateMachine="ce";}let state="0";const buffer={};buffer["parenthesisLevel"]=0;input=input.replace(/\n/g," ");input=input.replace(/[\u2212\u2013\u2014\u2010]/g,"-");input=input.replace(/[\u2026]/g,"...");let lastInput;let watchdog=10;const output=[];while(true){if(lastInput!==input){watchdog=10;lastInput=input;}else {watchdog--;}const machine=mhchemParser.stateMachines[stateMachine];const t=machine.transitions[state]||machine.transitions["*"];iterateTransitions:for(let i=0;i<t.length;i++){const matches=mhchemParser.patterns.match_(t[i].pattern,input);if(matches){const task=t[i].task;for(let iA=0;iA<task.action_.length;iA++){var o;if(machine.actions[task.action_[iA].type_]){o=machine.actions[task.action_[iA].type_](buffer,matches.match_,task.action_[iA].option);}else if(mhchemParser.actions[task.action_[iA].type_]){o=mhchemParser.actions[task.action_[iA].type_](buffer,matches.match_,task.action_[iA].option);}else {throw ["MhchemBugA","mhchem bug A. Please report. ("+task.action_[iA].type_+")"]}mhchemParser.concatArray(output,o);}state=task.nextState||state;if(input.length>0){if(!task.revisit){input=matches.remainder;}if(!task.toContinue){break iterateTransitions}}else {return output}}}if(watchdog<=0){throw ["MhchemBugU","mhchem bug U. Please report."]}}},concatArray:function(a,b){if(b){if(Array.isArray(b)){for(let iB=0;iB<b.length;iB++){a.push(b[iB]);}}else {a.push(b);}}},patterns:{patterns:{empty:/^$/,else:/^./,else2:/^./,space:/^\s/,"space A":/^\s(?=[A-Z\\$])/,space$:/^\s$/,"a-z":/^[a-z]/,x:/^x/,x$:/^x$/,i$:/^i$/,letters:/^(?:[a-zA-Z\u03B1-\u03C9\u0391-\u03A9?@]|(?:\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))))+/,"\\greek":/^\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega|Gamma|Delta|Theta|Lambda|Xi|Pi|Sigma|Upsilon|Phi|Psi|Omega)(?:\s+|\{\}|(?![a-zA-Z]))/,"one lowercase latin letter $":/^(?:([a-z])(?:$|[^a-zA-Z]))$/,"$one lowercase latin letter$ $":/^\$(?:([a-z])(?:$|[^a-zA-Z]))\$$/,"one lowercase greek letter $":/^(?:\$?[\u03B1-\u03C9]\$?|\$?\\(?:alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\s*\$?)(?:\s+|\{\}|(?![a-zA-Z]))$/,digits:/^[0-9]+/,"-9.,9":/^[+\-]?(?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))/,"-9.,9 no missing 0":/^[+\-]?[0-9]+(?:[.,][0-9]+)?/,"(-)(9.,9)(e)(99)":function(input){const m=input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))?(\((?:[0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+))\))?(?:([eE]|\s*(\*|x|\\times|\u00D7)\s*10\^)([+\-]?[0-9]+|\{[+\-]?[0-9]+\}))?/);if(m&&m[0]){return {match_:m.splice(1),remainder:input.substr(m[0].length)}}return null},"(-)(9)^(-9)":function(input){const m=input.match(/^(\+\-|\+\/\-|\+|\-|\\pm\s?)?([0-9]+(?:[,.][0-9]+)?|[0-9]*(?:\.[0-9]+)?)\^([+\-]?[0-9]+|\{[+\-]?[0-9]+\})/);if(m&&m[0]){return {match_:m.splice(1),remainder:input.substr(m[0].length)}}return null},"state of aggregation $":function(input){const a=mhchemParser.patterns.findObserveGroups(input,"",/^\([a-z]{1,3}(?=[\),])/,")","");if(a&&a.remainder.match(/^($|[\s,;\)\]\}])/)){return a}const m=input.match(/^(?:\((?:\\ca\s?)?\$[amothc]\$\))/);if(m){return {match_:m[0],remainder:input.substr(m[0].length)}}return null},"_{(state of aggregation)}$":/^_\{(\([a-z]{1,3}\))\}/,"{[(":/^(?:\\\{|\[|\()/,")]}":/^(?:\)|\]|\\\})/,", ":/^[,;]\s*/,",":/^[,;]/,".":/^[.]/,". ":/^([.\u22C5\u00B7\u2022])\s*/,"...":/^\.\.\.(?=$|[^.])/,"* ":/^([*])\s*/,"^{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^{","","","}")},"^($...$)":function(input){return mhchemParser.patterns.findObserveGroups(input,"^","$","$","")},"^a":/^\^([0-9]+|[^\\_])/,"^\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"^\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"^",/^\\[a-zA-Z]+\{/,"}","")},"^\\x":/^\^(\\[a-zA-Z]+)\s*/,"^(-1)":/^\^(-?\d+)/,"'":/^'/,"_{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_{","","","}")},"_($...$)":function(input){return mhchemParser.patterns.findObserveGroups(input,"_","$","$","")},_9:/^_([+\-]?[0-9]+|[^\\])/,"_\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"_\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"_",/^\\[a-zA-Z]+\{/,"}","")},"_\\x":/^_(\\[a-zA-Z]+)\s*/,"^_":/^(?:\^(?=_)|\_(?=\^)|[\^_]$)/,"{}":/^\{\}/,"{...}":function(input){return mhchemParser.patterns.findObserveGroups(input,"","{","}","")},"{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"{","","","}")},"$...$":function(input){return mhchemParser.patterns.findObserveGroups(input,"","$","$","")},"${(...)}$":function(input){return mhchemParser.patterns.findObserveGroups(input,"${","","","}$")},"$(...)$":function(input){return mhchemParser.patterns.findObserveGroups(input,"$","","","$")},"=<>":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(input){return mhchemParser.patterns.findObserveGroups(input,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",true)},"\\x{}":function(input){return mhchemParser.patterns.findObserveGroups(input,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}0":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color{","","","}")},"\\color{(...)}{(...)}1":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color{","","","}","{","","","}")},"\\color(...){(...)}2":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(input){return mhchemParser.patterns.findObserveGroups(input,"\\ce{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(input){let match;match=input.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}const a=mhchemParser.patterns.findObserveGroups(input,"","$","$","");if(a){match=a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}}return null},amount2:function(input){return this["amount"](input)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(input){if(input.match(/^\([a-z]+\)$/)){return null}const match=input.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);if(match){return {match_:match[0],remainder:input.substr(match[0].length)}}return null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(input,begExcl,begIncl,endIncl,endExcl,beg2Excl,beg2Incl,end2Incl,end2Excl,combine){const _match=function(input,pattern){if(typeof pattern==="string"){if(input.indexOf(pattern)!==0){return null}return pattern}const match=input.match(pattern);if(!match){return null}return match[0]};const _findObserveGroups=function(input,i,endChars){let braces=0;while(i<input.length){const a=input.charAt(i);const match=_match(input.substr(i),endChars);if(match!==null&&braces===0){return {endMatchBegin:i,endMatchEnd:i+match.length}}if(a==="{"){braces++;}else if(a==="}"){if(braces===0){throw ["ExtraCloseMissingOpen","Extra close brace or missing open brace"]}else {braces--;}}i++;}if(braces>0){return null}return null};let match=_match(input,begExcl);if(match===null){return null}input=input.substr(match.length);match=_match(input,begIncl);if(match===null){return null}const e=_findObserveGroups(input,match.length,endIncl||endExcl);if(e===null){return null}const match1=input.substring(0,endIncl?e.endMatchEnd:e.endMatchBegin);if(!(beg2Excl||beg2Incl)){return {match_:match1,remainder:input.substr(e.endMatchEnd)}}const group2=this.findObserveGroups(input.substr(e.endMatchEnd),beg2Excl,beg2Incl,end2Incl,end2Excl);if(group2===null){return null}const matchRet=[match1,group2.match_];return {match_:combine?matchRet.join(""):matchRet,remainder:group2.remainder}},match_:function(m,input){const pattern=mhchemParser.patterns.patterns[m];if(pattern===undefined){throw ["MhchemBugP","mhchem bug P. Please report. ("+m+")"]}else if(typeof pattern==="function"){return mhchemParser.patterns.patterns[m](input)}else {const match=input.match(pattern);if(match){let mm;if(match[2]){mm=[match[1],match[2]];}else if(match[1]){mm=match[1];}else {mm=match[0];}return {match_:mm,remainder:input.substr(match[0].length)}}return null}}},actions:{"a=":function(buffer,m){buffer.a=(buffer.a||"")+m;},"b=":function(buffer,m){buffer.b=(buffer.b||"")+m;},"p=":function(buffer,m){buffer.p=(buffer.p||"")+m;},"o=":function(buffer,m){buffer.o=(buffer.o||"")+m;},"q=":function(buffer,m){buffer.q=(buffer.q||"")+m;},"d=":function(buffer,m){buffer.d=(buffer.d||"")+m;},"rm=":function(buffer,m){buffer.rm=(buffer.rm||"")+m;},"text=":function(buffer,m){buffer.text_=(buffer.text_||"")+m;},insert:function(buffer,m,a){return {type_:a}},"insert+p1":function(buffer,m,a){return {type_:a,p1:m}},"insert+p1+p2":function(buffer,m,a){return {type_:a,p1:m[0],p2:m[1]}},copy:function(buffer,m){return m},rm:function(buffer,m){return {type_:"rm",p1:m||""}},text:function(buffer,m){return mhchemParser.go(m,"text")},"{text}":function(buffer,m){const ret=["{"];mhchemParser.concatArray(ret,mhchemParser.go(m,"text"));ret.push("}");return ret},"tex-math":function(buffer,m){return mhchemParser.go(m,"tex-math")},"tex-math tight":function(buffer,m){return mhchemParser.go(m,"tex-math tight")},bond:function(buffer,m,k){return {type_:"bond",kind_:k||m}},"color0-output":function(buffer,m){return {type_:"color0",color:m[0]}},ce:function(buffer,m){return mhchemParser.go(m)},"1/2":function(buffer,m){const ret=[];if(m.match(/^[+\-]/)){ret.push(m.substr(0,1));m=m.substr(1);}const n=m.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/);n[1]=n[1].replace(/\$/g,"");ret.push({type_:"frac",p1:n[1],p2:n[2]});if(n[3]){n[3]=n[3].replace(/\$/g,"");ret.push({type_:"tex-math",p1:n[3]});}return ret},"9,9":function(buffer,m){return mhchemParser.go(m,"9,9")}},createTransitions:function(o){let pattern;let state;let stateArray;let i;const transitions={};for(pattern in o){for(state in o[pattern]){stateArray=state.split("|");o[pattern][state].stateArray=stateArray;for(i=0;i<stateArray.length;i++){transitions[stateArray[i]]=[];}}}for(pattern in o){for(state in o[pattern]){stateArray=o[pattern][state].stateArray||[];for(i=0;i<stateArray.length;i++){const p=o[pattern][state];if(p.action_){p.action_=[].concat(p.action_);for(let k=0;k<p.action_.length;k++){if(typeof p.action_[k]==="string"){p.action_[k]={type_:p.action_[k]};}}}else {p.action_=[];}const patternArray=pattern.split("|");for(let j=0;j<patternArray.length;j++){if(stateArray[i]==="*"){for(const t in transitions){transitions[t].push({pattern:patternArray[j],task:p});}}else {transitions[stateArray[i]].push({pattern:patternArray[j],task:p});}}}}}return transitions},stateMachines:{}};mhchemParser.stateMachines={ce:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},else:{"0|1|2":{action_:"beginsWithBond=false",revisit:true,toContinue:true}},oxidation$:{0:{action_:"oxidation-output"}},CMT:{r:{action_:"rdt=",nextState:"rt"},rd:{action_:"rqt=",nextState:"rdt"}},arrowUpDown:{"0|1|2|as":{action_:["sb=false","output","operator"],nextState:"1"}},uprightEntities:{"0|1|2":{action_:["o=","output"],nextState:"1"}},orbital:{"0|1|2|3":{action_:"o=",nextState:"o"}},"->":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:false},nextState:"2"},q:{action_:{type_:"- after o/d",option:false},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:true},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{}},space:{a:{nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". |* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}0":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:true},as:{action_:["output","sb=true"],nextState:"1",revisit:true},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:true},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(buffer,m){let ret;if((buffer.d||"").match(/^[0-9]+$/)){const tmp=buffer.d;buffer.d=undefined;ret=this["output"](buffer);buffer.b=tmp;}else {ret=this["output"](buffer);}mhchemParser.actions["o="](buffer,m);return ret},"d= kv":function(buffer,m){buffer.d=m;buffer.dType="kv";},"charge or bond":function(buffer,m){if(buffer["beginsWithBond"]){const ret=[];mhchemParser.concatArray(ret,this["output"](buffer));mhchemParser.concatArray(ret,mhchemParser.actions["bond"](buffer,m,"-"));return ret}buffer.d=m;},"- after o/d":function(buffer,m,isAfterD){let c1=mhchemParser.patterns.match_("orbital",buffer.o||"");const c2=mhchemParser.patterns.match_("one lowercase greek letter $",buffer.o||"");const c3=mhchemParser.patterns.match_("one lowercase latin letter $",buffer.o||"");const c4=mhchemParser.patterns.match_("$one lowercase latin letter$ $",buffer.o||"");const hyphenFollows=m==="-"&&(c1&&c1.remainder===""||c2||c3||c4);if(hyphenFollows&&!buffer.a&&!buffer.b&&!buffer.p&&!buffer.d&&!buffer.q&&!c1&&c3){buffer.o="$"+buffer.o+"$";}const ret=[];if(hyphenFollows){mhchemParser.concatArray(ret,this["output"](buffer));ret.push({type_:"hyphen"});}else {c1=mhchemParser.patterns.match_("digits",buffer.d||"");if(isAfterD&&c1&&c1.remainder===""){mhchemParser.concatArray(ret,mhchemParser.actions["d="](buffer,m));mhchemParser.concatArray(ret,this["output"](buffer));}else {mhchemParser.concatArray(ret,this["output"](buffer));mhchemParser.concatArray(ret,mhchemParser.actions["bond"](buffer,m,"-"));}}return ret},"a to o":function(buffer){buffer.o=buffer.a;buffer.a=undefined;},"sb=true":function(buffer){buffer.sb=true;},"sb=false":function(buffer){buffer.sb=false;},"beginsWithBond=true":function(buffer){buffer["beginsWithBond"]=true;},"beginsWithBond=false":function(buffer){buffer["beginsWithBond"]=false;},"parenthesisLevel++":function(buffer){buffer["parenthesisLevel"]++;},"parenthesisLevel--":function(buffer){buffer["parenthesisLevel"]--;},"state of aggregation":function(buffer,m){return {type_:"state of aggregation",p1:mhchemParser.go(m,"o")}},comma:function(buffer,m){const a=m.replace(/\s*$/,"");const withSpace=a!==m;if(withSpace&&buffer["parenthesisLevel"]===0){return {type_:"comma enumeration L",p1:a}}return {type_:"comma enumeration M",p1:a}},output:function(buffer,m,entityFollows){let ret;if(!buffer.r){ret=[];if(!buffer.a&&!buffer.b&&!buffer.p&&!buffer.o&&!buffer.q&&!buffer.d&&!entityFollows);else {if(buffer.sb){ret.push({type_:"entitySkip"});}if(!buffer.o&&!buffer.q&&!buffer.d&&!buffer.b&&!buffer.p&&entityFollows!==2){buffer.o=buffer.a;buffer.a=undefined;}else if(!buffer.o&&!buffer.q&&!buffer.d&&(buffer.b||buffer.p)){buffer.o=buffer.a;buffer.d=buffer.b;buffer.q=buffer.p;buffer.a=buffer.b=buffer.p=undefined;}else {if(buffer.o&&buffer.dType==="kv"&&mhchemParser.patterns.match_("d-oxidation$",buffer.d||"")){buffer.dType="oxidation";}else if(buffer.o&&buffer.dType==="kv"&&!buffer.q){buffer.dType=undefined;}}ret.push({type_:"chemfive",a:mhchemParser.go(buffer.a,"a"),b:mhchemParser.go(buffer.b,"bd"),p:mhchemParser.go(buffer.p,"pq"),o:mhchemParser.go(buffer.o,"o"),q:mhchemParser.go(buffer.q,"pq"),d:mhchemParser.go(buffer.d,buffer.dType==="oxidation"?"oxidation":"bd"),dType:buffer.dType});}}else {let rd;if(buffer.rdt==="M"){rd=mhchemParser.go(buffer.rd,"tex-math");}else if(buffer.rdt==="T"){rd=[{type_:"text",p1:buffer.rd||""}];}else {rd=mhchemParser.go(buffer.rd);}let rq;if(buffer.rqt==="M"){rq=mhchemParser.go(buffer.rq,"tex-math");}else if(buffer.rqt==="T"){rq=[{type_:"text",p1:buffer.rq||""}];}else {rq=mhchemParser.go(buffer.rq);}ret={type_:"arrow",r:buffer.r,rd:rd,rq:rq};}for(const p in buffer){if(p!=="parenthesisLevel"&&p!=="beginsWithBond"){delete buffer[p];}}return ret},"oxidation-output":function(buffer,m){const ret=["{"];mhchemParser.concatArray(ret,mhchemParser.go(m,"oxidation"));ret.push("}");return ret},"frac-output":function(buffer,m){return {type_:"frac-ce",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"overset-output":function(buffer,m){return {type_:"overset",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"underset-output":function(buffer,m){return {type_:"underset",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"underbrace-output":function(buffer,m){return {type_:"underbrace",p1:mhchemParser.go(m[0]),p2:mhchemParser.go(m[1])}},"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1])}},"r=":function(buffer,m){buffer.r=m;},"rdt=":function(buffer,m){buffer.rdt=m;},"rd=":function(buffer,m){buffer.rd=m;},"rqt=":function(buffer,m){buffer.rqt=m;},"rq=":function(buffer,m){buffer.rq=m;},operator:function(buffer,m,p1){return {type_:"operator",kind_:p1||m}}}},a:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:true}},"$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:true}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"{text}"}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(buffer){if(buffer.text_){const ret={type_:"text",p1:buffer.text_};for(const p in buffer){delete buffer[p];}return ret}}}},pq:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{nextState:"!f",revisit:true}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{nextState:"f",revisit:true}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"!f",revisit:true}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(buffer,m){return {type_:"state of aggregation subscript",p1:mhchemParser.go(m,"o")}},"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1],"pq")}}}},bd:{transitions:mhchemParser.createTransitions({empty:{"*":{}},x$:{0:{nextState:"!f",revisit:true}},formula$:{0:{nextState:"f",revisit:true}},else:{0:{nextState:"!f",revisit:true}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(buffer,m){return {type_:"color",color1:m[0],color2:mhchemParser.go(m[1],"bd")}}}},oxidation:{transitions:mhchemParser.createTransitions({empty:{"*":{}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(buffer,m){return {type_:"roman numeral",p1:m||""}}}},"tex-math":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(buffer){if(buffer.o){const ret={type_:"tex-math",p1:buffer.o};for(const p in buffer){delete buffer[p];}return ret}}}},"tex-math tight":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(buffer,m){buffer.o=(buffer.o||"")+"{"+m+"}";},output:function(buffer){if(buffer.o){const ret={type_:"tex-math",p1:buffer.o};for(const p in buffer){delete buffer[p];}return ret}}}},"9,9":{transitions:mhchemParser.createTransitions({empty:{"*":{}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return {type_:"commaDecimal"}}}},pu:{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(buffer,m){const ret=[];if(m[0]==="+-"||m[0]==="+/-"){ret.push("\\pm ");}else if(m[0]){ret.push(m[0]);}if(m[1]){mhchemParser.concatArray(ret,mhchemParser.go(m[1],"pu-9,9"));if(m[2]){if(m[2].match(/[,.]/)){mhchemParser.concatArray(ret,mhchemParser.go(m[2],"pu-9,9"));}else {ret.push(m[2]);}}m[3]=m[4]||m[3];if(m[3]){m[3]=m[3].trim();if(m[3]==="e"||m[3].substr(0,1)==="*"){ret.push({type_:"cdot"});}else {ret.push({type_:"times"});}}}if(m[3]){ret.push("10^{"+m[5]+"}");}return ret},"number^":function(buffer,m){const ret=[];if(m[0]==="+-"||m[0]==="+/-"){ret.push("\\pm ");}else if(m[0]){ret.push(m[0]);}mhchemParser.concatArray(ret,mhchemParser.go(m[1],"pu-9,9"));ret.push("^{"+m[2]+"}");return ret},operator:function(buffer,m,p1){return {type_:"operator",kind_:p1||m}},space:function(){return {type_:"pu-space-1"}},output:function(buffer){let ret;const md=mhchemParser.patterns.match_("{(...)}",buffer.d||"");if(md&&md.remainder===""){buffer.d=md.match_;}const mq=mhchemParser.patterns.match_("{(...)}",buffer.q||"");if(mq&&mq.remainder===""){buffer.q=mq.match_;}if(buffer.d){buffer.d=buffer.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C");buffer.d=buffer.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");}if(buffer.q){buffer.q=buffer.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C");buffer.q=buffer.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");const b5={d:mhchemParser.go(buffer.d,"pu"),q:mhchemParser.go(buffer.q,"pu")};if(buffer.o==="//"){ret={type_:"pu-frac",p1:b5.d,p2:b5.q};}else {ret=b5.d;if(b5.d.length>1||b5.q.length>1){ret.push({type_:" / "});}else {ret.push({type_:"/"});}mhchemParser.concatArray(ret,b5.q);}}else {ret=mhchemParser.go(buffer.d,"pu-2");}for(const p in buffer){delete buffer[p];}return ret}}},"pu-2":{transitions:mhchemParser.createTransitions({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return {type_:"tight cdot"}},"^(-1)":function(buffer,m){buffer.rm+="^{"+m+"}";},space:function(){return {type_:"pu-space-2"}},output:function(buffer){let ret=[];if(buffer.rm){const mrm=mhchemParser.patterns.match_("{(...)}",buffer.rm||"");if(mrm&&mrm.remainder===""){ret=mhchemParser.go(mrm.match_,"pu");}else {ret={type_:"rm",p1:buffer.rm};}}for(const p in buffer){delete buffer[p];}return ret}}},"pu-9,9":{transitions:mhchemParser.createTransitions({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return {type_:"commaDecimal"}},"output-0":function(buffer){const ret=[];buffer.text_=buffer.text_||"";if(buffer.text_.length>4){let a=buffer.text_.length%3;if(a===0){a=3;}for(let i=buffer.text_.length-3;i>0;i-=3){ret.push(buffer.text_.substr(i,3));ret.push({type_:"1000 separator"});}ret.push(buffer.text_.substr(0,a));ret.reverse();}else {ret.push(buffer.text_);}for(const p in buffer){delete buffer[p];}return ret},"output-o":function(buffer){const ret=[];buffer.text_=buffer.text_||"";if(buffer.text_.length>4){const a=buffer.text_.length-3;for(var i=0;i<a;i+=3){ret.push(buffer.text_.substr(i,3));ret.push({type_:"1000 separator"});}ret.push(buffer.text_.substr(i));}else {ret.push(buffer.text_);}for(const p in buffer){delete buffer[p];}return ret}}}};var texify={go:function(input,isInner){if(!input){return ""}let res="";let cee=false;for(let i=0;i<input.length;i++){const inputi=input[i];if(typeof inputi==="string"){res+=inputi;}else {res+=texify._go2(inputi);if(inputi.type_==="1st-level escape"){cee=true;}}}if(!isInner&&!cee&&res){res="{"+res+"}";}return res},_goInner:function(input){if(!input){return input}return texify.go(input,true)},_go2:function(buf){let res;switch(buf.type_){case "chemfive":res="";var b5={a:texify._goInner(buf.a),b:texify._goInner(buf.b),p:texify._goInner(buf.p),o:texify._goInner(buf.o),q:texify._goInner(buf.q),d:texify._goInner(buf.d)};if(b5.a){if(b5.a.match(/^[+\-]/)){b5.a="{"+b5.a+"}";}res+=b5.a+"\\,";}if(b5.b||b5.p){res+="{\\vphantom{X}}";res+="^{\\hphantom{"+(b5.b||"")+"}}_{\\hphantom{"+(b5.p||"")+"}}";res+="{\\vphantom{X}}";res+="^{\\smash[t]{\\vphantom{2}}\\mathllap{"+(b5.b||"")+"}}";res+="_{\\vphantom{2}\\mathllap{\\smash[t]{"+(b5.p||"")+"}}}";}if(b5.o){if(b5.o.match(/^[+\-]/)){b5.o="{"+b5.o+"}";}res+=b5.o;}if(buf.dType==="kv"){if(b5.d||b5.q){res+="{\\vphantom{X}}";}if(b5.d){res+="^{"+b5.d+"}";}if(b5.q){res+="_{\\smash[t]{"+b5.q+"}}";}}else if(buf.dType==="oxidation"){if(b5.d){res+="{\\vphantom{X}}";res+="^{"+b5.d+"}";}if(b5.q){res+="{\\vphantom{X}}";res+="_{\\smash[t]{"+b5.q+"}}";}}else {if(b5.q){res+="{\\vphantom{X}}";res+="_{\\smash[t]{"+b5.q+"}}";}if(b5.d){res+="{\\vphantom{X}}";res+="^{"+b5.d+"}";}}break;case "rm":res="\\mathrm{"+buf.p1+"}";break;case "text":if(buf.p1.match(/[\^_]/)){buf.p1=buf.p1.replace(" ","~").replace("-","\\text{-}");res="\\mathrm{"+buf.p1+"}";}else {res="\\text{"+buf.p1+"}";}break;case "roman numeral":res="\\mathrm{"+buf.p1+"}";break;case "state of aggregation":res="\\mskip2mu "+texify._goInner(buf.p1);break;case "state of aggregation subscript":res="\\mskip1mu "+texify._goInner(buf.p1);break;case "bond":res=texify._getBond(buf.kind_);if(!res){throw ["MhchemErrorBond","mhchem Error. Unknown bond type ("+buf.kind_+")"]}break;case "frac":var c="\\frac{"+buf.p1+"}{"+buf.p2+"}";res="\\mathchoice{\\textstyle"+c+"}{"+c+"}{"+c+"}{"+c+"}";break;case "pu-frac":var d="\\frac{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";res="\\mathchoice{\\textstyle"+d+"}{"+d+"}{"+d+"}{"+d+"}";break;case "tex-math":res=buf.p1+" ";break;case "frac-ce":res="\\frac{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "overset":res="\\overset{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "underset":res="\\underset{"+texify._goInner(buf.p1)+"}{"+texify._goInner(buf.p2)+"}";break;case "underbrace":res="\\underbrace{"+texify._goInner(buf.p1)+"}_{"+texify._goInner(buf.p2)+"}";break;case "color":res="{\\color{"+buf.color1+"}{"+texify._goInner(buf.color2)+"}}";break;case "color0":res="\\color{"+buf.color+"}";break;case "arrow":var b6={rd:texify._goInner(buf.rd),rq:texify._goInner(buf.rq)};var arrow="\\x"+texify._getArrow(buf.r);if(b6.rq){arrow+="[{"+b6.rq+"}]";}if(b6.rd){arrow+="{"+b6.rd+"}";}else {arrow+="{}";}res=arrow;break;case "operator":res=texify._getOperator(buf.kind_);break;case "1st-level escape":res=buf.p1+" ";break;case "space":res=" ";break;case "entitySkip":res="~";break;case "pu-space-1":res="~";break;case "pu-space-2":res="\\mkern3mu ";break;case "1000 separator":res="\\mkern2mu ";break;case "commaDecimal":res="{,}";break;case "comma enumeration L":res="{"+buf.p1+"}\\mkern6mu ";break;case "comma enumeration M":res="{"+buf.p1+"}\\mkern3mu ";break;case "comma enumeration S":res="{"+buf.p1+"}\\mkern1mu ";break;case "hyphen":res="\\text{-}";break;case "addition compound":res="\\,{\\cdot}\\,";break;case "electron dot":res="\\mkern1mu \\bullet\\mkern1mu ";break;case "KV x":res="{\\times}";break;case "prime":res="\\prime ";break;case "cdot":res="\\cdot ";break;case "tight cdot":res="\\mkern1mu{\\cdot}\\mkern1mu ";break;case "times":res="\\times ";break;case "circa":res="{\\sim}";break;case "^":res="uparrow";break;case "v":res="downarrow";break;case "ellipsis":res="\\ldots ";break;case "/":res="/";break;case " / ":res="\\,/\\,";break;default:throw ["MhchemBugT","mhchem bug T. Please report."]}return res},_getArrow:function(a){switch(a){case "->":return "rightarrow";case "→":return "rightarrow";case "⟶":return "rightarrow";case "<-":return "leftarrow";case "<->":return "leftrightarrow";case "<-->":return "rightleftarrows";case "<=>":return "rightleftharpoons";case "⇌":return "rightleftharpoons";case "<=>>":return "rightequilibrium";case "<<=>":return "leftequilibrium";default:throw ["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(a){switch(a){case "-":return "{-}";case "1":return "{-}";case "=":return "{=}";case "2":return "{=}";case "#":return "{\\equiv}";case "3":return "{\\equiv}";case "~":return "{\\tripledash}";case "~-":return "{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}";case "~=":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case "~--":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case "-~-":return "{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}";case "...":return "{{\\cdot}{\\cdot}{\\cdot}}";case "....":return "{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case "->":return "{\\rightarrow}";case "<-":return "{\\leftarrow}";case "<":return "{<}";case ">":return "{>}";default:throw ["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(a){switch(a){case "+":return " {}+{} ";case "-":return " {}-{} ";case "=":return " {}={} ";case "<":return " {}<{} ";case ">":return " {}>{} ";case "<<":return " {}\\ll{} ";case ">>":return " {}\\gg{} ";case "\\pm":return " {}\\pm{} ";case "\\approx":return " {}\\approx{} ";case "$\\approx$":return " {}\\approx{} ";case "v":return " \\downarrow{} ";case "(v)":return " \\downarrow{} ";case "^":return " \\uparrow{} ";case "(^)":return " \\uparrow{} ";default:throw ["MhchemBugT","mhchem bug T. Please report."]}}};
1449
+
1450
+ katex.__defineMacro("\\ce",function(context){return chemParse(context.consumeArgs(1)[0],"ce")});katex.__defineMacro("\\pu",function(context){return chemParse(context.consumeArgs(1)[0],"pu")});katex.__defineMacro("\\tripledash","{\\vphantom{-}\\raisebox{2.56mu}{$\\mkern2mu"+"\\tiny\\text{-}\\mkern1mu\\text{-}\\mkern1mu\\text{-}\\mkern2mu$}}");
1451
+
1452
+ function detectTexErrors(content){const errors=[];const ast=PerseusMarkdown.parse(content,{});PerseusMarkdown.traverseContent(ast,node=>{if(node.type==="math"||node.type==="blockMath"){const texContent=preprocessTex(node.content);try{katex.renderToString(texContent,{colorIsTextColor:true});}catch(e){errors.push({math:texContent,message:e.message});}}});return errors}
1453
+
1454
+ const{HUD: HUD$1}=components;class ArticleEditor extends React.Component{componentDidMount(){this._updateIssues();this._updatePreviewFrames();}componentDidUpdate(prevProps){if(prevProps.json!==this.props.json||prevProps.issues!==this.props.issues){this._updateIssues();}this._updatePreviewFrames();}_updateIssues(){const sections=this.props.json instanceof Array?this.props.json:[this.props.json];const allLinterIssues=[];sections.forEach(section=>{const parsed=PerseusMarkdown.parse(section.content??"",{});const linterContext={content:section.content,widgets:section.widgets,stack:[]};const sectionIssues=PerseusLinter.runLinter(parsed,linterContext,false)?.map(linterWarning=>{if(linterWarning.rule==="inaccessible-widget"){return WARNINGS.inaccessibleWidget(linterWarning.metadata?.widgetType??"unknown",linterWarning.metadata?.widgetId??"unknown")}return WARNINGS.genericLinterWarning(linterWarning.rule,linterWarning.message,linterWarning.severity)})??[];allLinterIssues.push(...sectionIssues);const texErrors=detectTexErrors(section.content??"");const texIssues=texErrors.map((error,index)=>WARNINGS.texError(error.math,error.message,index));allLinterIssues.push(...texIssues);});this.setState({issues:[...this.props.issues??[],...allLinterIssues]});}_updatePreviewFrames(){if(this.props.mode==="preview"){this.refs["frame-all"].sendNewData({type:"article-all",data:this._sections().map((section,i)=>{return this._apiOptionsForSection(section,i)})});}else if(this.props.mode==="edit"){this._sections().forEach((section,i)=>{this.refs["frame-"+i].sendNewData({type:"article",data:this._apiOptionsForSection(section,i)});});}}_apiOptionsForSection(section,sectionIndex){const editor=this.refs[`editor${sectionIndex}`];return {apiOptions:{...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true},json:section,useNewStyles:this.props.useNewStyles,linterContext:{contentType:"article",highlightLint:this.state.highlightLint,paths:this.props.contentPaths},legacyPerseusLint:editor?editor.getSaveWarnings():[]}}_sections(){const json=this.props.json;return json instanceof Array?json:[json]}_renderEditor(){const{imageUploader,sectionImageUploadGenerator}=this.props;const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true};const sections=this._sections();const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[sections.map((section,i)=>{return [jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsxs("fieldset",{disabled:editingDisabled,children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx(IssuesPanel,{apiOptions:this.props.apiOptions,issues:this.state.issues}),jsxRuntimeExports.jsxs("div",{className:"pod-title",children:["Section ",i+1,jsxRuntimeExports.jsxs("div",{style:{display:"inline-block",float:"right"},children:[sectionImageUploadGenerator(i),jsxRuntimeExports.jsx(SectionControlButton,{icon:plusIcon,disabled:editingDisabled,onClick:()=>{this._handleAddSectionAfter(i);},title:"Add a new section after this one"}),i+1<sections.length&&jsxRuntimeExports.jsx(SectionControlButton,{icon:arrowCircleDownIcon,disabled:editingDisabled,onClick:()=>{this._handleMoveSectionLater(i);},title:"Move this section down"}),i>0&&jsxRuntimeExports.jsx(SectionControlButton,{icon:arrowCircleUpIcon,disabled:editingDisabled,onClick:()=>{this._handleMoveSectionEarlier(i);},title:"Move this section up"}),jsxRuntimeExports.jsx(SectionControlButton,{icon:trashIcon,disabled:editingDisabled,onClick:()=>{const msg="Are you sure you "+"want to delete section "+(i+1)+"?";if(confirm(msg)){this._handleRemoveSection(i);}},title:"Delete this section"})]})]}),jsxRuntimeExports.jsx(Editor,{...section,apiOptions:apiOptions,imageUploader:imageUploader,onChange:newProps=>this._handleEditorChange(i,newProps),placeholder:"Type your section text here...",ref:"editor"+i})]}),jsxRuntimeExports.jsx("div",{className:"editor-preview",children:this._renderIframePreview(i,true)})]})},i)]}),this._renderAddSection(editingDisabled),this._renderLinterHUD()]})}_renderAddSection(editingDisabled){return jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,disabled:editingDisabled,kind:"tertiary","aria-label":"Add a section",onClick:()=>{this._handleAddSectionAfter(this._sections().length-1);},children:"Add a section"})})})}_renderLinterHUD(){return jsxRuntimeExports.jsx(HUD$1,{message:"Style warnings",enabled:this.state.highlightLint,onClick:()=>{this.setState({highlightLint:!this.state.highlightLint});}})}_renderIframePreview(i,nochrome){const isMobile=this.props.screen==="phone"||this.props.screen==="tablet";return jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.screen,nochrome:nochrome,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:"frame-"+i,datasetKey:"mobile",datasetValue:isMobile,seamless:nochrome,url:this.props.previewURL},this.props.screen)})}_renderPreviewMode(){return jsxRuntimeExports.jsx("div",{className:"standalone-preview",children:this._renderIframePreview("all",false)})}_handleMoveSectionEarlier(i){if(i===0){return}const sections=[...this._sections()];const section=sections[i];sections.splice(i,1);sections.splice(i-1,0,section);this.props.onChange({json:sections});}_handleMoveSectionLater(i){const sections=[...this._sections()];if(i+1===sections.length){return}const section=sections[i];sections.splice(i,1);sections.splice(i+1,0,section);this.props.onChange({json:sections});}_handleAddSectionAfter(i){const sections=_.clone(this.serialize());const newSection=i>=0?{widgets:sections[i].widgets}:{};sections.splice(i+1,0,newSection);this.props.onChange({json:sections});}_handleRemoveSection(i){const sections=[...this._sections()];sections.splice(i,1);this.props.onChange({json:sections});}serialize(){if(this.props.mode==="edit"){return this._sections().map((section,i)=>{return this.refs["editor"+i].serialize()})}if(this.props.mode==="preview"||this.props.mode==="json"){return this.props.json}throw new PerseusError("Could not serialize; mode "+this.props.mode+" not found",Errors.Internal)}getSaveWarnings(){if(this.props.mode!=="edit"){throw new PerseusError("Can only get save warnings in edit mode.",Errors.NotAllowed)}return this._sections().map((section,i)=>{return this.refs["editor"+i].getSaveWarnings()})}render(){const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsx(Dependencies.DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{className:"framework-perseus perseus-article-editor",children:[this.props.mode==="edit"&&this._renderEditor(),this.props.mode==="preview"&&this._renderPreviewMode(),this.props.mode==="json"&&jsxRuntimeExports.jsxs("div",{className:"json-editor",children:[jsxRuntimeExports.jsx("div",{className:"json-editor-warning",children:jsxRuntimeExports.jsx("span",{children:"Warning: Editing in this mode can lead to broken articles!"})}),jsxRuntimeExports.jsx(JsonEditor,{multiLine:true,onChange:this._handleJsonChange,value:this.props.json,editingDisabled:editingDisabled})]})]})})}constructor(...args){super(...args),this.state={highlightLint:true,issues:[]},this._handleJsonChange=newJson=>{this.props.onChange({json:newJson});},this._handleEditorChange=(i,newProps)=>{const sections=[...this._sections()];sections[i]={...sections[i],...newProps};this.props.onChange({json:sections});};}}ArticleEditor.defaultProps={contentPaths:[],json:[{}],mode:"edit",screen:"desktop",sectionImageUploadGenerator:()=>jsxRuntimeExports.jsx("span",{}),useNewStyles:false};
1453
1455
 
1454
1456
  const iconChevronRight={path:"M62.808 49.728q0 3.36-2.352 5.88l-41.72 41.664q-2.352 2.408-5.768 2.408t-5.768-2.408l-4.872-4.76q-2.352-2.52-2.352-5.88t2.352-5.712l31.08-31.136-31.08-31.024q-2.352-2.52-2.352-5.88t2.352-5.712l4.872-4.76q2.296-2.408 5.768-2.408t5.768 2.408l41.72 41.664q2.352 2.296 2.352 5.656z",width:63.034,height:100};const iconCircleArrowDown={path:"M50.046 83.676q1.767 0 2.907-1.14l29.526-29.526q1.197-1.197 1.197-2.907t-1.197-2.964l-5.928-5.928q-1.197-1.14-2.964-1.14t-2.907 1.14l-12.312 12.312l0-32.661q0-1.71-1.254-2.964t-2.907-1.254l-8.322 0q-1.71 0-2.964 1.254t-1.254 2.964l0 32.661l-12.312-12.312q-1.197-1.254-2.907-1.254t-2.907 1.254l-5.928 5.928q-1.197 1.197-1.197 2.964t1.197 2.907l29.469 29.526q1.197 1.14 2.964 1.14zm49.989-33.63q.057 13.623-6.669 25.137t-18.24 18.183-25.08 6.669-25.137-6.726q-11.514-6.726-18.183-18.183-6.726-11.571-6.726-25.137t6.726-25.08 18.24-18.24 25.08-6.669q13.566 0 25.08 6.726 11.514 6.669 18.24 18.183t6.669 25.137z",width:100,height:100};const iconCircleArrowUp={path:"M54.207 83.391q1.653 0 2.907-1.254t1.254-2.907l0-32.718l12.312 12.312q1.254 1.254 2.964 1.254t2.907-1.254l5.928-5.928q1.197-1.197 1.14-2.964 0-1.767-1.14-2.907l-29.526-29.526q-1.197-1.14-2.907-1.14t-2.964 1.14l-29.469 29.526q-1.197 1.254-1.197 2.964t1.197 2.907l5.928 5.928q1.197 1.197 2.907 1.197t2.907-1.197l12.312-12.312l0 32.718q0 1.653 1.254 2.907t2.964 1.254l8.322 0zm45.828-33.345q.057 13.623-6.669 25.137t-18.24 18.183-25.08 6.669-25.137-6.726q-11.514-6.726-18.183-18.183-6.726-11.571-6.726-25.137t6.726-25.08 18.24-18.24 25.08-6.669q13.566 0 25.08 6.726 11.514 6.669 18.24 18.183t6.669 25.137z",width:100,height:100};const iconDesktop={path:"M94.208 52.119l0-43.746q0-.69-.506-1.15t-1.196-.506l-84.088 0q-.69 0-1.196.506t-.506 1.15l0 43.746q0 .69.506 1.196t1.196.506l84.088 0q.69 0 1.196-.506t.506-1.196zm6.716-43.746l0 57.224q0 3.45-2.484 5.934t-5.934 2.484l-28.566 0q0 3.128 2.53 7.774.828 1.61.828 2.622t-1.012 2.07q-1.012 1.012-2.346.966l-26.91 0q-1.38 0-2.392-1.012t-1.012-2.024q0-1.058 1.656-4.14t1.748-6.256l-28.612 0q-3.45 0-5.934-2.484t-2.484-5.934l0-57.224q0-3.45 2.484-5.934t5.934-2.438l84.088 0q3.45 0 5.98 2.438 2.438 2.484 2.438 5.934z",width:100,height:86.648};const iconMobilePhone={path:"M36.04 89.557q0-2.584-1.836-4.42t-4.42-1.836-4.352 1.836q-1.836 1.836-1.836 4.42t1.836 4.352 4.42 1.836q2.652-.068 4.42-1.836t1.768-4.352zm16.184-12.444l0-54.74q0-1.088-.748-1.768t-1.768-.68l-39.78 0q-1.088 0-1.768.748t-.68 1.7l0 54.74q0 1.02.748 1.768t1.7.68l39.78 0q1.02-.068 1.768-.748t.748-1.7zm-14.892-65.892q0-1.224-1.292-1.292l-12.444 0q-1.224.068-1.224 1.292t1.224 1.224l12.444 0q1.292 0 1.292-1.224zm22.372-1.292l0 79.628q0 3.944-2.992 6.936t-7.004 2.992l-39.78 0q-4.012 0-7.004-2.924-2.924-2.924-2.924-7.004l0-79.628q0-4.012 2.924-6.936t7.004-2.992l39.78 0q4.012-.068 7.004 2.924t2.992 7.004z",width:60.013,height:100};const iconPlus={path:"M99.758 43.09l0 13.578q0 2.852-1.984 4.836t-4.836 1.984l-29.45 0l0 29.45q0 2.852-1.984 4.836t-4.836 1.984l-13.578 0q-2.852 0-4.836-1.984t-1.984-4.836l0-29.45l-29.45 0q-2.852 0-4.836-1.984t-1.984-4.836l0-13.578q0-2.852 1.984-4.836t4.836-1.984l29.45 0l0-29.45q0-2.852 1.984-4.836t4.836-1.984l13.578 0q2.852 0 4.836 1.984t1.984 4.836l0 29.45l29.45 0q2.852 0 4.836 1.984t1.984 4.836z",width:100,height:100};const iconTablet={path:"M45.322 90.706q0-1.86-1.302-3.224-1.364-1.364-3.224-1.364t-3.224 1.364-1.302 3.224q0 1.86 1.364 3.224 1.302 1.364 3.162 1.302 1.86.062 3.224-1.302t1.302-3.224zm27.218-11.346l0-68.014q0-.93-.682-1.612t-1.55-.682l-58.962 0q-.93 0-1.612.682t-.682 1.612l0 68.014q0 .93.682 1.612t1.612.62l58.962 0q.992-.062 1.612-.682t.62-1.55zm9.114-68.014l0 77.066q0 4.65-3.348 7.998t-7.998 3.348l-58.962 0q-4.65 0-7.998-3.348t-3.348-7.998l0-77.066q0-4.65 3.348-7.998t7.998-3.348l58.962 0q4.65 0 7.998 3.348t3.348 7.998z",width:81.852,height:100};
1455
1457
 
@@ -1461,11 +1463,11 @@ const splitDiff=function(diffEntries){const lines=[];let currentLine=[];_.each(d
1461
1463
 
1462
1464
  const statusFor=function(chunk){if(chunk.added){return "added"}if(chunk.removed){return "removed"}return "unchanged"};const splitUpChunk=chunk=>_.map(chunk.value,value=>{return {value:value,status:statusFor(chunk)}});const mapcat=function(lst,fn){return _.flatten(_.map(lst,fn),true)};const ArrayDiff=new JSDiff.Diff;ArrayDiff.tokenize=array=>_.map(array,elem=>[elem]);ArrayDiff.join=(a,b)=>a.concat(b);ArrayDiff.equals=_.isEqual;const flattenChunks=chunks=>mapcat(chunks,splitUpChunk);const stringArrayDiff=function(a,b){const diffResult=ArrayDiff.diff(a,b);const flattened=flattenChunks(diffResult);return {before:_.filter(flattened,entry=>entry.status!=="added"),after:_.filter(flattened,entry=>entry.status!=="removed")}};
1463
1465
 
1464
- const{SvgImage: SvgImage$3}=components;const BEFORE$1="before";const AFTER$1="after";const IMAGE_REGEX=/http.*?\.png|web\+graphie[^)]*/g;const imagesInString=function(str){return str.match(IMAGE_REGEX)||[]};const classFor=function(entry,ifAdded,ifRemoved){if(entry.added){return ifAdded}if(entry.removed){return ifRemoved}return ""};class ImageDiffSide extends React.Component{render(){return jsxRuntimeExports.jsx("div",{children:_.map(this.props.images,(entry,index)=>{const className=classNames({image:true,"image-unchanged":entry.status==="unchanged","image-added":entry.status==="added","image-removed":entry.status==="removed"});return jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx("div",{className:className,children:jsxRuntimeExports.jsx(SvgImage$3,{src:entry.value,title:entry.value,allowZoom:false})})},index)})})}}ImageDiffSide.propTypes={images:PropTypes.arrayOf(PropTypes.shape({})).isRequired};class TextDiff extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({collapsed:nextProps.before===nextProps.after});}render(){const diffed=JSDiff.diffWords(this.props.before,this.props.after);const lines=splitDiff(diffed);const beforeImages=imagesInString(this.props.before);const afterImages=imagesInString(this.props.after);const images=stringArrayDiff(beforeImages,afterImages);const renderedLines=_.map(lines,line=>{const contents={};contents.before=_(line).map(function(entry,i){return jsxRuntimeExports.jsx("span",{className:classFor(entry,"not-present","removed dark"),children:entry.value},i)});contents.after=_(line).map(function(entry,i){return jsxRuntimeExports.jsx("span",{className:classFor(entry,"added dark","not-present"),children:entry.value},i)});return contents});const className=classNames({"diff-row":true,collapsed:this.state.collapsed});return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"diff-header",children:this.props.title}),jsxRuntimeExports.jsx("div",{className:"diff-header",children:this.props.title}),jsxRuntimeExports.jsx("div",{className:"diff-body ui-helper-clearfix",children:_.map([BEFORE$1,AFTER$1],(side,index)=>{return jsxRuntimeExports.jsxs("div",{className:"diff-row "+side,children:[!this.state.collapsed&&_.map(renderedLines,(line,lineNum)=>{const changed=line[side].length>1;const lineClass=classNames({"diff-line":true,added:side===AFTER$1&&changed,removed:side===BEFORE$1&&changed});return jsxRuntimeExports.jsx("div",{className:lineClass,children:line[side]},lineNum)}),!this.state.collapsed&&jsxRuntimeExports.jsx(ImageDiffSide,{images:images[side]})]},index)})}),_.map([BEFORE$1,AFTER$1],(side,index)=>{return jsxRuntimeExports.jsx("div",{className:className+" "+side,onClick:this.handleExpand,children:this.state.collapsed&&jsxRuntimeExports.jsx("span",{children:jsxRuntimeExports.jsxs("span",{className:"expand-button",children:[" ","[ show unmodified ]"," "]})})},index)})]})}constructor(...args){super(...args),this.state={collapsed:this.props.before===this.props.after},this.handleExpand=()=>{this.setState({collapsed:false});};}}TextDiff.propTypes={after:PropTypes.string,before:PropTypes.string,title:PropTypes.string.isRequired};TextDiff.defaultProps={after:"",before:""};
1466
+ const{SvgImage: SvgImage$2}=components;const BEFORE$1="before";const AFTER$1="after";const IMAGE_REGEX=/http.*?\.png|web\+graphie[^)]*/g;const imagesInString=function(str){return str.match(IMAGE_REGEX)||[]};const classFor=function(entry,ifAdded,ifRemoved){if(entry.added){return ifAdded}if(entry.removed){return ifRemoved}return ""};class ImageDiffSide extends React.Component{render(){return jsxRuntimeExports.jsx("div",{children:_.map(this.props.images,(entry,index)=>{const className=classNames({image:true,"image-unchanged":entry.status==="unchanged","image-added":entry.status==="added","image-removed":entry.status==="removed"});return jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx("div",{className:className,children:jsxRuntimeExports.jsx(SvgImage$2,{src:entry.value,title:entry.value,allowZoom:false})})},index)})})}}ImageDiffSide.propTypes={images:PropTypes.arrayOf(PropTypes.shape({})).isRequired};class TextDiff extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({collapsed:nextProps.before===nextProps.after});}render(){const diffed=JSDiff.diffWords(this.props.before,this.props.after);const lines=splitDiff(diffed);const beforeImages=imagesInString(this.props.before);const afterImages=imagesInString(this.props.after);const images=stringArrayDiff(beforeImages,afterImages);const renderedLines=_.map(lines,line=>{const contents={};contents.before=_(line).map(function(entry,i){return jsxRuntimeExports.jsx("span",{className:classFor(entry,"not-present","removed dark"),children:entry.value},i)});contents.after=_(line).map(function(entry,i){return jsxRuntimeExports.jsx("span",{className:classFor(entry,"added dark","not-present"),children:entry.value},i)});return contents});const className=classNames({"diff-row":true,collapsed:this.state.collapsed});return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"diff-header",children:this.props.title}),jsxRuntimeExports.jsx("div",{className:"diff-header",children:this.props.title}),jsxRuntimeExports.jsx("div",{className:"diff-body ui-helper-clearfix",children:_.map([BEFORE$1,AFTER$1],(side,index)=>{return jsxRuntimeExports.jsxs("div",{className:"diff-row "+side,children:[!this.state.collapsed&&_.map(renderedLines,(line,lineNum)=>{const changed=line[side].length>1;const lineClass=classNames({"diff-line":true,added:side===AFTER$1&&changed,removed:side===BEFORE$1&&changed});return jsxRuntimeExports.jsx("div",{className:lineClass,children:line[side]},lineNum)}),!this.state.collapsed&&jsxRuntimeExports.jsx(ImageDiffSide,{images:images[side]})]},index)})}),_.map([BEFORE$1,AFTER$1],(side,index)=>{return jsxRuntimeExports.jsx("div",{className:className+" "+side,onClick:this.handleExpand,children:this.state.collapsed&&jsxRuntimeExports.jsx("span",{children:jsxRuntimeExports.jsxs("span",{className:"expand-button",children:[" ","[ show unmodified ]"," "]})})},index)})]})}constructor(...args){super(...args),this.state={collapsed:this.props.before===this.props.after},this.handleExpand=()=>{this.setState({collapsed:false});};}}TextDiff.propTypes={after:PropTypes.string,before:PropTypes.string,title:PropTypes.string.isRequired};TextDiff.defaultProps={after:"",before:""};
1465
1467
 
1466
1468
  const UNCHANGED$1="unchanged";const CHANGED="changed";const ADDED="added";const REMOVED="removed";const valueEntry=function(before,after,key){let status;if(before===after){status=UNCHANGED$1;}else if(before===undefined){status=ADDED;}else if(after===undefined){status=REMOVED;}else {status=CHANGED;}return {after:JSON.stringify(after),before:JSON.stringify(before),children:[],key:key,status:status}};const objectEntry=function(before,after,key){const beforeKeys=_.isObject(before)?_(before).keys():[];const afterKeys=_.isObject(after)?_(after).keys():[];const keys=_.union(beforeKeys,afterKeys);const children=_.map(keys,function(key){return performDiff((before||{})[key],(after||{})[key],key)});let status;if(before===undefined){status=ADDED;}else if(after===undefined){status=REMOVED;}else {const changed=_.any(children,function(child){return child.status!==UNCHANGED$1});status=changed?CHANGED:UNCHANGED$1;}return {after:"",before:"",children:children,key:key,status:status}};const performDiff=function(before,after,key){if(typeof before==="object"||typeof after==="object"){return objectEntry(before,after,key)}return valueEntry(before,after,key)};
1467
1469
 
1468
- const{SvgImage: SvgImage$2}=components;const indentationFromDepth=function(depth){return (depth-1)*20};const BEFORE="before";const AFTER="after";const UNCHANGED="unchanged";class DiffSide extends React.Component{render(){const className=classNames(this.props.className,{"diff-row":true,before:this.props.side===BEFORE,after:this.props.side===AFTER});return jsxRuntimeExports.jsx("div",{className:className,children:jsxRuntimeExports.jsxs("div",{style:{paddingLeft:indentationFromDepth(this.props.depth)},children:[this.props.showKey&&this.props.propKey+": ",jsxRuntimeExports.jsx("span",{className:"inner-value dark "+this.props.className,children:this.props.value})]})})}}DiffSide.propTypes={className:PropTypes.string.isRequired,depth:PropTypes.number.isRequired,propKey:PropTypes.string.isRequired,showKey:PropTypes.bool.isRequired,side:PropTypes.oneOf([BEFORE,AFTER]).isRequired,value:PropTypes.string};class CollapsedRow extends React.Component{render(){const self=this;return jsxRuntimeExports.jsx("div",{onClick:self.props.onClick,style:{clear:"both"},children:_.map([BEFORE,AFTER],function(side){return jsxRuntimeExports.jsx("div",{className:"diff-row collapsed "+side,children:jsxRuntimeExports.jsx("div",{style:{paddingLeft:indentationFromDepth(self.props.depth)},children:jsxRuntimeExports.jsx("span",{children:" [ show unmodified ] "})})},side)})})}}CollapsedRow.propTypes={depth:PropTypes.number,onClick:PropTypes.func.isRequired};CollapsedRow.defaultProps={depth:0};class DiffEntry extends React.Component{render(){const entry=this.props.entry;const propertyDeleted=entry.status==="removed";const propertyAdded=entry.status==="added";const propertyChanged=entry.status==="changed";const hasChildren=entry.children.length>0;const leftClass=classNames({removed:propertyDeleted||propertyChanged&&!hasChildren,dark:propertyDeleted,"blank-space":propertyAdded});const rightClass=classNames({added:propertyAdded||propertyChanged&&!hasChildren,dark:propertyAdded,"blank-space":propertyDeleted});let shownChildren;if(this.state.expanded){shownChildren=entry.children;}else {shownChildren=_(entry.children).select(function(child){return child.status!==UNCHANGED});}let collapsed=shownChildren.length<entry.children.length;if(entry.children.length===shownChildren.length+1){shownChildren=entry.children;collapsed=false;}const self=this;return jsxRuntimeExports.jsxs("div",{children:[entry.key&&jsxRuntimeExports.jsxs("div",{style:{clear:"both"},children:[jsxRuntimeExports.jsx(DiffSide,{side:BEFORE,className:leftClass,depth:this.props.depth,propKey:entry.key,showKey:!propertyAdded,value:entry.before}),jsxRuntimeExports.jsx(DiffSide,{side:AFTER,className:rightClass,depth:this.props.depth,propKey:entry.key,showKey:!propertyDeleted,value:entry.after})]}),_.map(shownChildren,function(child){return jsxRuntimeExports.jsx(DiffEntry,{depth:self.props.depth+1,entry:child,expanded:self.state.expanded},child.key)}),collapsed&&jsxRuntimeExports.jsx(CollapsedRow,{depth:this.props.depth+1,onClick:this.expand})]})}constructor(...args){super(...args),this.state={expanded:this.props.expanded},this.expand=()=>{this.setState({expanded:true});};}}DiffEntry.propTypes={depth:PropTypes.number,entry:PropTypes.shape({after:PropTypes.string,before:PropTypes.string,children:PropTypes.arrayOf(PropTypes.any),key:PropTypes.string}),expanded:PropTypes.bool};DiffEntry.defaultProps={depth:0};class ImageWidgetDiff extends React.Component{render(){const{before,after}=this.props;const beforeSrc=before.options&&before.options.backgroundImage?before.options.backgroundImage.url:"";const afterSrc=after.options&&after.options.backgroundImage?after.options.backgroundImage.url:"";return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"diff-row before",children:beforeSrc&&jsxRuntimeExports.jsx("div",{className:classNames({image:true,"image-unchanged":beforeSrc===afterSrc,"image-removed":beforeSrc!==afterSrc}),children:jsxRuntimeExports.jsx(SvgImage$2,{src:beforeSrc,title:beforeSrc,allowZoom:false})})}),jsxRuntimeExports.jsx("div",{className:"diff-row after",children:afterSrc&&jsxRuntimeExports.jsx("div",{className:classNames({image:true,"image-unchanged":beforeSrc===afterSrc,"image-added":beforeSrc!==afterSrc}),children:jsxRuntimeExports.jsx(SvgImage$2,{src:afterSrc,title:afterSrc,allowZoom:false})})})]})}}ImageWidgetDiff.propTypes={after:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}).isRequired,before:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}).isRequired};class WidgetDiff extends React.Component{render(){const{after,before,title,type}=this.props;const diff=performDiff(before,after);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"diff-header",children:title}),jsxRuntimeExports.jsx("div",{className:"diff-header",children:title}),jsxRuntimeExports.jsxs("div",{className:"diff-body ui-helper-clearfix",children:[type==="image"&&jsxRuntimeExports.jsx(ImageWidgetDiff,{before:before,after:after}),jsxRuntimeExports.jsx(DiffEntry,{entry:diff})]})]})}}WidgetDiff.propTypes={after:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}),before:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}),title:PropTypes.string.isRequired,type:PropTypes.string};WidgetDiff.defaultProps={after:{},before:{},type:""};
1470
+ const{SvgImage: SvgImage$1}=components;const indentationFromDepth=function(depth){return (depth-1)*20};const BEFORE="before";const AFTER="after";const UNCHANGED="unchanged";class DiffSide extends React.Component{render(){const className=classNames(this.props.className,{"diff-row":true,before:this.props.side===BEFORE,after:this.props.side===AFTER});return jsxRuntimeExports.jsx("div",{className:className,children:jsxRuntimeExports.jsxs("div",{style:{paddingLeft:indentationFromDepth(this.props.depth)},children:[this.props.showKey&&this.props.propKey+": ",jsxRuntimeExports.jsx("span",{className:"inner-value dark "+this.props.className,children:this.props.value})]})})}}DiffSide.propTypes={className:PropTypes.string.isRequired,depth:PropTypes.number.isRequired,propKey:PropTypes.string.isRequired,showKey:PropTypes.bool.isRequired,side:PropTypes.oneOf([BEFORE,AFTER]).isRequired,value:PropTypes.string};class CollapsedRow extends React.Component{render(){const self=this;return jsxRuntimeExports.jsx("div",{onClick:self.props.onClick,style:{clear:"both"},children:_.map([BEFORE,AFTER],function(side){return jsxRuntimeExports.jsx("div",{className:"diff-row collapsed "+side,children:jsxRuntimeExports.jsx("div",{style:{paddingLeft:indentationFromDepth(self.props.depth)},children:jsxRuntimeExports.jsx("span",{children:" [ show unmodified ] "})})},side)})})}}CollapsedRow.propTypes={depth:PropTypes.number,onClick:PropTypes.func.isRequired};CollapsedRow.defaultProps={depth:0};class DiffEntry extends React.Component{render(){const entry=this.props.entry;const propertyDeleted=entry.status==="removed";const propertyAdded=entry.status==="added";const propertyChanged=entry.status==="changed";const hasChildren=entry.children.length>0;const leftClass=classNames({removed:propertyDeleted||propertyChanged&&!hasChildren,dark:propertyDeleted,"blank-space":propertyAdded});const rightClass=classNames({added:propertyAdded||propertyChanged&&!hasChildren,dark:propertyAdded,"blank-space":propertyDeleted});let shownChildren;if(this.state.expanded){shownChildren=entry.children;}else {shownChildren=_(entry.children).select(function(child){return child.status!==UNCHANGED});}let collapsed=shownChildren.length<entry.children.length;if(entry.children.length===shownChildren.length+1){shownChildren=entry.children;collapsed=false;}const self=this;return jsxRuntimeExports.jsxs("div",{children:[entry.key&&jsxRuntimeExports.jsxs("div",{style:{clear:"both"},children:[jsxRuntimeExports.jsx(DiffSide,{side:BEFORE,className:leftClass,depth:this.props.depth,propKey:entry.key,showKey:!propertyAdded,value:entry.before}),jsxRuntimeExports.jsx(DiffSide,{side:AFTER,className:rightClass,depth:this.props.depth,propKey:entry.key,showKey:!propertyDeleted,value:entry.after})]}),_.map(shownChildren,function(child){return jsxRuntimeExports.jsx(DiffEntry,{depth:self.props.depth+1,entry:child,expanded:self.state.expanded},child.key)}),collapsed&&jsxRuntimeExports.jsx(CollapsedRow,{depth:this.props.depth+1,onClick:this.expand})]})}constructor(...args){super(...args),this.state={expanded:this.props.expanded},this.expand=()=>{this.setState({expanded:true});};}}DiffEntry.propTypes={depth:PropTypes.number,entry:PropTypes.shape({after:PropTypes.string,before:PropTypes.string,children:PropTypes.arrayOf(PropTypes.any),key:PropTypes.string}),expanded:PropTypes.bool};DiffEntry.defaultProps={depth:0};class ImageWidgetDiff extends React.Component{render(){const{before,after}=this.props;const beforeSrc=before.options&&before.options.backgroundImage?before.options.backgroundImage.url:"";const afterSrc=after.options&&after.options.backgroundImage?after.options.backgroundImage.url:"";return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"diff-row before",children:beforeSrc&&jsxRuntimeExports.jsx("div",{className:classNames({image:true,"image-unchanged":beforeSrc===afterSrc,"image-removed":beforeSrc!==afterSrc}),children:jsxRuntimeExports.jsx(SvgImage$1,{src:beforeSrc,title:beforeSrc,allowZoom:false})})}),jsxRuntimeExports.jsx("div",{className:"diff-row after",children:afterSrc&&jsxRuntimeExports.jsx("div",{className:classNames({image:true,"image-unchanged":beforeSrc===afterSrc,"image-added":beforeSrc!==afterSrc}),children:jsxRuntimeExports.jsx(SvgImage$1,{src:afterSrc,title:afterSrc,allowZoom:false})})})]})}}ImageWidgetDiff.propTypes={after:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}).isRequired,before:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}).isRequired};class WidgetDiff extends React.Component{render(){const{after,before,title,type}=this.props;const diff=performDiff(before,after);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"diff-header",children:title}),jsxRuntimeExports.jsx("div",{className:"diff-header",children:title}),jsxRuntimeExports.jsxs("div",{className:"diff-body ui-helper-clearfix",children:[type==="image"&&jsxRuntimeExports.jsx(ImageWidgetDiff,{before:before,after:after}),jsxRuntimeExports.jsx(DiffEntry,{entry:diff})]})]})}}WidgetDiff.propTypes={after:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}),before:PropTypes.shape({options:PropTypes.objectOf(PropTypes.any)}),title:PropTypes.string.isRequired,type:PropTypes.string};WidgetDiff.defaultProps={after:{},before:{},type:""};
1469
1471
 
1470
1472
  const filterWidgetInfo=function(widgetInfo,showAlignmentOptions){const{alignment,graded,options,type}=widgetInfo||{};const filteredWidgetInfo={options};if(showAlignmentOptions&&CoreWidgetRegistry.getSupportedAlignments(type).length>1){filteredWidgetInfo.alignment=alignment;}if(type==="transformer"){filteredWidgetInfo.graded=graded;}if(Widgets.supportsStaticMode(type)){filteredWidgetInfo.static=widgetInfo?.static??undefined;}return filteredWidgetInfo};class RendererDiff extends React.Component{render(){const{after,before,showAlignmentOptions,showSeparator,title}=this.props;let textDiff;let widgetsDiff;if(before.content||after.content){textDiff=jsxRuntimeExports.jsx(TextDiff,{before:before.content,after:after.content,title:title});}const beforeWidgets=Object.keys(before.widgets??{}).filter(widget=>before.content.includes(widget));const afterWidgets=Object.keys(after.widgets??{}).filter(widget=>after.content.includes(widget));if(beforeWidgets.length||afterWidgets.length){const widgets=_.union(beforeWidgets,afterWidgets);widgetsDiff=widgets.map(widget=>jsxRuntimeExports.jsx(WidgetDiff,{before:filterWidgetInfo(before.widgets?.[widget],showAlignmentOptions),after:filterWidgetInfo(after.widgets?.[widget],showAlignmentOptions),title:widget,type:(before.widgets?.[widget]??{}).type||(after.widgets?.[widget]??{}).type},widget));}return jsxRuntimeExports.jsxs("div",{children:[textDiff,widgetsDiff,showSeparator&&jsxRuntimeExports.jsx("div",{className:"diff-separator"})]})}}RendererDiff.defaultProps={after:{content:"",images:{},widgets:{}},before:{content:"",images:{},widgets:{}},showAlignmentOptions:false,showSeparator:false};
1471
1473
 
@@ -1473,11 +1475,11 @@ const rendererProps=PropTypes.shape({content:PropTypes.string,images:PropTypes.o
1473
1475
 
1474
1476
  const itemProps=PropTypes.shape({question:PropTypes.shape({}).isRequired,answerArea:PropTypes.shape({}).isRequired,hints:PropTypes.arrayOf(PropTypes.any).isRequired});class ItemDiff extends React.Component{render(){const{before,after}=this.props;const hintCount=Math.max(before.hints.length,after.hints.length);const question=jsxRuntimeExports.jsx(RendererDiff,{before:before.question,after:after.question,title:"Question",showAlignmentOptions:false,showSeparator:true});const extras=jsxRuntimeExports.jsx(WidgetDiff,{before:before.answerArea,after:after.answerArea,title:"Question extras"});const hints=_.times(hintCount,function(n){return jsxRuntimeExports.jsx(RendererDiff,{before:n<before.hints.length?before.hints[n]:undefined,after:n<after.hints.length?after.hints[n]:undefined,title:`Hint ${n+1}`,showAlignmentOptions:false,showSeparator:n<hintCount-1},n)});return jsxRuntimeExports.jsx(Dependencies.DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{className:"framework-perseus",children:[question,extras,hints&&jsxRuntimeExports.jsx("div",{className:"diff-separator"}),hints]})})}}ItemDiff.propTypes={after:itemProps.isRequired,before:itemProps.isRequired};
1475
1477
 
1476
- const{InfoTip: InfoTip$q,InlineIcon: InlineIcon$2}=components;class HintEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor "+this.props.className,children:[this.props.showTitle&&jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.editor,apiOptions:this.props.apiOptions,widgets:this.props.widgets||undefined,content:this.props.content||undefined,images:this.props.images,replace:this.props.replace,placeholder:"Type your hint here...",imageUploader:this.props.imageUploader,onChange:this.props.onChange,widgetIsOpen:this.props.widgetIsOpen},this.props.itemId),jsxRuntimeExports.jsxs("div",{className:"hint-controls-container clearfix",children:[this.props.showMoveButtons&&jsxRuntimeExports.jsxs("span",{className:"reorder-hints",children:[jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isLast?"hidden":"",onClick:_.partial(this.props.onMove,1),children:jsxRuntimeExports.jsx(InlineIcon$2,{...iconCircleArrowDown})})," ",jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isFirst?"hidden":"",onClick:_.partial(this.props.onMove,-1),children:jsxRuntimeExports.jsx(InlineIcon$2,{...iconCircleArrowUp})})," ",this.props.isLast&&jsxRuntimeExports.jsx(InfoTip$q,{children:jsxRuntimeExports.jsx("p",{children:"The last hint is automatically bolded."})})]}),jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.replace,onChange:this.handleChange}),"Replace previous hint",this.props.showRemoveButton&&jsxRuntimeExports.jsxs("button",{type:"button",className:"remove-hint simple-button orange",onClick:this.props.onRemove,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconTrash}),"Remove this hint"," "]})]})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.handleChange=e=>{this.props.onChange({replace:e.target.checked});},this.focus=()=>{this.editor.current?.focus();},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)};}}HintEditor.defaultProps={className:"",content:"",replace:false,showMoveButtons:true,showTitle:true,showRemoveButton:true};class CombinedHintEditor extends React.Component{componentDidMount(){this.updatePreview();}componentDidUpdate(){this.updatePreview();}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";return jsxRuntimeExports.jsxs("div",{className:"perseus-combined-hint-editor "+"perseus-editor-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(HintEditor,{ref:this.editor,itemId:this.props.itemId,isFirst:this.props.isFirst,isLast:this.props.isLast,widgets:this.props.hint.widgets,content:this.props.hint.content,images:this.props.hint.images,replace:this.props.hint.replace,imageUploader:this.props.imageUploader,onChange:this.props.onChange,onRemove:this.props.onRemove,onMove:this.props.onMove,apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:this.frame,datasetKey:"mobile",datasetValue:isMobile,seamless:true,url:this.props.previewURL})})})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.frame=React.createRef(),this.updatePreview=()=>{const shouldBold=this.props.isLast&&!/\*\*/.test(this.props.hint.content);this.frame.current?.sendNewData({type:"hint",data:{hint:this.props.hint,bold:shouldBold,pos:this.props.pos,apiOptions:this.props.apiOptions,linterContext:{contentType:"hint",highlightLint:this.props.highlightLint,paths:this.props.contentPaths}}});},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)},this.focus=()=>{this.editor.current?.focus();};}}CombinedHintEditor.defaultProps={highlightLint:false};class CombinedHintsEditor extends React.Component{render(){const{itemId,hints}=this.props;const editingDisabled=this.props.apiOptions?.editingDisabled??false;const hintElems=_.map(hints,function(hint,i){return jsxRuntimeExports.jsx("fieldset",{disabled:editingDisabled,children:jsxRuntimeExports.jsx(CombinedHintEditor,{ref:"hintEditor"+i,isFirst:i===0,isLast:i+1===hints.length,itemId:itemId,hint:hint,pos:i,imageUploader:this.props.imageUploader,onChange:this.handleHintChange.bind(this,i),onRemove:this.handleHintRemove.bind(this,i),onMove:this.handleHintMove.bind(this,i),deviceType:this.props.deviceType,apiOptions:this.props.apiOptions,highlightLint:this.props.highlightLint,previewURL:this.props.previewURL,contentPaths:[],widgetIsOpen:this.props.widgetIsOpen})},"hintEditor"+i)},this);return jsxRuntimeExports.jsxs("div",{className:"perseus-hints-editor perseus-editor-table",children:[hintElems,jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"add-hint-container perseus-editor-left-cell",children:jsxRuntimeExports.jsxs("button",{type:"button",className:"add-hint simple-button orange",disabled:editingDisabled,onClick:this.addHint,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconPlus})," Add a hint"]})})})]})}constructor(...args){super(...args),this.handleHintChange=(i,newProps,cb,silent)=>{const hints=[...this.props.hints];hints[i]=_.extend({},this.serializeHint(i,{keepDeletedWidgets:true}),newProps);this.props.onChange({hints:hints},cb,silent);},this.handleHintRemove=i=>{if(!confirm("Are you sure you want to delete this hint?")){return}const hints=[...this.props.hints];hints.splice(i,1);this.props.onChange({hints:hints});},this.handleHintMove=(i,dir)=>{const hints=[...this.props.hints];const hint=hints.splice(i,1)[0];hints.splice(i+dir,0,hint);this.props.onChange({hints:hints},()=>{this.refs["hintEditor"+(i+dir)].focus();});},this.addHint=()=>{const hint={content:"",images:{},widgets:{}};const hints=[...this.props.hints,hint];this.props.onChange({hints:hints},()=>{const i=hints.length-1;this.refs["hintEditor"+i].focus();});},this.getSaveWarnings=()=>{return _.chain(this.props.hints).map((hint,i)=>{return _.map(this.refs["hintEditor"+i].getSaveWarnings(),issue=>"Hint "+(i+1)+": "+issue)}).flatten(true).value()},this.serialize=options=>{return this.props.hints.map((hint,i)=>{return this.serializeHint(i,options)})},this.serializeHint=(index,options)=>{return this.refs["hintEditor"+index].serialize(options)};}}CombinedHintsEditor.HintEditor=HintEditor;CombinedHintsEditor.defaultProps={onChange:()=>{},hints:[],highlightLint:false};
1478
+ const{InfoTip: InfoTip$p,InlineIcon: InlineIcon$2}=components;class HintEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-hint-editor "+this.props.className,children:[this.props.showTitle&&jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Hint"}),jsxRuntimeExports.jsx(Editor,{ref:this.editor,apiOptions:this.props.apiOptions,widgets:this.props.widgets||undefined,content:this.props.content||undefined,images:this.props.images,replace:this.props.replace,placeholder:"Type your hint here...",imageUploader:this.props.imageUploader,onChange:this.props.onChange,widgetIsOpen:this.props.widgetIsOpen},this.props.itemId),jsxRuntimeExports.jsxs("div",{className:"hint-controls-container clearfix",children:[this.props.showMoveButtons&&jsxRuntimeExports.jsxs("span",{className:"reorder-hints",children:[jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isLast?"hidden":"",onClick:_.partial(this.props.onMove,1),children:jsxRuntimeExports.jsx(InlineIcon$2,{...iconCircleArrowDown})})," ",jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isFirst?"hidden":"",onClick:_.partial(this.props.onMove,-1),children:jsxRuntimeExports.jsx(InlineIcon$2,{...iconCircleArrowUp})})," ",this.props.isLast&&jsxRuntimeExports.jsx(InfoTip$p,{children:jsxRuntimeExports.jsx("p",{children:"The last hint is automatically bolded."})})]}),jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.replace,onChange:this.handleChange}),"Replace previous hint",this.props.showRemoveButton&&jsxRuntimeExports.jsxs("button",{type:"button",className:"remove-hint simple-button orange",onClick:this.props.onRemove,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconTrash}),"Remove this hint"," "]})]})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.handleChange=e=>{this.props.onChange({replace:e.target.checked});},this.focus=()=>{this.editor.current?.focus();},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)};}}HintEditor.defaultProps={className:"",content:"",replace:false,showMoveButtons:true,showTitle:true,showRemoveButton:true};class CombinedHintEditor extends React.Component{componentDidMount(){this.updatePreview();}componentDidUpdate(){this.updatePreview();}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";return jsxRuntimeExports.jsxs("div",{className:"perseus-combined-hint-editor "+"perseus-editor-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsx(HintEditor,{ref:this.editor,itemId:this.props.itemId,isFirst:this.props.isFirst,isLast:this.props.isLast,widgets:this.props.hint.widgets,content:this.props.hint.content,images:this.props.hint.images,replace:this.props.hint.replace,imageUploader:this.props.imageUploader,onChange:this.props.onChange,onRemove:this.props.onRemove,onMove:this.props.onMove,apiOptions:this.props.apiOptions,widgetIsOpen:this.props.widgetIsOpen})}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:this.frame,datasetKey:"mobile",datasetValue:isMobile,seamless:true,url:this.props.previewURL})})})]})}constructor(...args){super(...args),this.editor=React.createRef(),this.frame=React.createRef(),this.updatePreview=()=>{const shouldBold=this.props.isLast&&!/\*\*/.test(this.props.hint.content);this.frame.current?.sendNewData({type:"hint",data:{hint:this.props.hint,bold:shouldBold,pos:this.props.pos,apiOptions:this.props.apiOptions,linterContext:{contentType:"hint",highlightLint:this.props.highlightLint,paths:this.props.contentPaths}}});},this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=options=>{return this.editor.current?.serialize(options)},this.focus=()=>{this.editor.current?.focus();};}}CombinedHintEditor.defaultProps={highlightLint:false};class CombinedHintsEditor extends React.Component{render(){const{itemId,hints}=this.props;const editingDisabled=this.props.apiOptions?.editingDisabled??false;const hintElems=_.map(hints,function(hint,i){return jsxRuntimeExports.jsx("fieldset",{disabled:editingDisabled,children:jsxRuntimeExports.jsx(CombinedHintEditor,{ref:"hintEditor"+i,isFirst:i===0,isLast:i+1===hints.length,itemId:itemId,hint:hint,pos:i,imageUploader:this.props.imageUploader,onChange:this.handleHintChange.bind(this,i),onRemove:this.handleHintRemove.bind(this,i),onMove:this.handleHintMove.bind(this,i),deviceType:this.props.deviceType,apiOptions:this.props.apiOptions,highlightLint:this.props.highlightLint,previewURL:this.props.previewURL,contentPaths:[],widgetIsOpen:this.props.widgetIsOpen})},"hintEditor"+i)},this);return jsxRuntimeExports.jsxs("div",{className:"perseus-hints-editor perseus-editor-table",children:[hintElems,jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"add-hint-container perseus-editor-left-cell",children:jsxRuntimeExports.jsxs("button",{type:"button",className:"add-hint simple-button orange",disabled:editingDisabled,onClick:this.addHint,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconPlus})," Add a hint"]})})})]})}constructor(...args){super(...args),this.handleHintChange=(i,newProps,cb,silent)=>{const hints=[...this.props.hints];hints[i]=_.extend({},this.serializeHint(i,{keepDeletedWidgets:true}),newProps);this.props.onChange({hints:hints},cb,silent);},this.handleHintRemove=i=>{if(!confirm("Are you sure you want to delete this hint?")){return}const hints=[...this.props.hints];hints.splice(i,1);this.props.onChange({hints:hints});},this.handleHintMove=(i,dir)=>{const hints=[...this.props.hints];const hint=hints.splice(i,1)[0];hints.splice(i+dir,0,hint);this.props.onChange({hints:hints},()=>{this.refs["hintEditor"+(i+dir)].focus();});},this.addHint=()=>{const hint={content:"",images:{},widgets:{}};const hints=[...this.props.hints,hint];this.props.onChange({hints:hints},()=>{const i=hints.length-1;this.refs["hintEditor"+i].focus();});},this.getSaveWarnings=()=>{return _.chain(this.props.hints).map((hint,i)=>{return _.map(this.refs["hintEditor"+i].getSaveWarnings(),issue=>"Hint "+(i+1)+": "+issue)}).flatten(true).value()},this.serialize=options=>{return this.props.hints.map((hint,i)=>{return this.serializeHint(i,options)})},this.serializeHint=(index,options)=>{return this.refs["hintEditor"+index].serialize(options)};}}CombinedHintsEditor.HintEditor=HintEditor;CombinedHintsEditor.defaultProps={onChange:()=>{},hints:[],highlightLint:false};
1477
1479
 
1478
- const{InfoTip: InfoTip$p}=components;class ItemExtrasEditor extends React.Component{shouldShowFinancialCalculatorOptions(){return this.props.financialCalculatorMonthlyPayment||this.props.financialCalculatorTotalAmount||this.props.financialCalculatorTimeToPayOff}render(){const{editingDisabled}=this.props;return jsxRuntimeExports.jsx("div",{className:"perseus-answer-editor",children:jsxRuntimeExports.jsxs("div",{className:"perseus-answer-options",children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show calculator",disabled:editingDisabled,infoTip:"Use the calculator when completing difficult calculations is NOT the intent of the question. DON’T use the calculator when testing the student’s ability to complete different types of computations.",checked:this.props.calculator,onChange:newCheckedState=>{this.props.onChange({calculator:newCheckedState});}}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show financial calculator",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a financial calculator, e.g., for answering financial questions. Once checked, requires at least one of the three options below to be checked.",checked:this.shouldShowFinancialCalculatorOptions(),onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState,financialCalculatorTotalAmount:newCheckedState,financialCalculatorTimeToPayOff:newCheckedState});}}),this.shouldShowFinancialCalculatorOptions()&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include monthly payment",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a monthly payment calculator; e.g., given a loan amount, interest rate, and term, what is the monthly payment?",checked:this.props.financialCalculatorMonthlyPayment,onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include total amount",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a total amount calculator; e.g., given a monthly payment, interest rate, and term, what is the total amount to be paid?",checked:this.props.financialCalculatorTotalAmount,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTotalAmount:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include time-to-pay-off",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a time to pay off calculator; e.g., given a loan amount, interest rate, and monthly payment, how long will it take to pay off the loan?",checked:this.props.financialCalculatorTimeToPayOff,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTimeToPayOff:newCheckedState});},indent:true})]}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show periodic table",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a periodic table of the elements, e.g., for answering chemistry questions.",checked:this.props.periodicTable,onChange:newCheckedState=>{this.props.onChange({periodicTable:newCheckedState,periodicTableWithKey:false});}}),this.props.periodicTable&&jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include key/legend with periodic table",disabled:editingDisabled,infoTip:"Include a key for HS courses; omit for AP chemistry.",checked:this.props.periodicTableWithKey,onChange:newCheckedState=>{this.props.onChange({periodicTableWithKey:newCheckedState});},indent:true})]})})}constructor(...args){super(...args),this.serialize=()=>{const data={...ItemExtrasEditor.defaultProps};for(const key of ItemExtras){data[key]=!!this.props[key];}return data};}}ItemExtrasEditor.defaultProps={calculator:false,financialCalculatorMonthlyPayment:false,financialCalculatorTotalAmount:false,financialCalculatorTimeToPayOff:false,periodicTable:false,periodicTableWithKey:false};const ItemExtraCheckbox=props=>jsxRuntimeExports.jsx(View,{style:[styles$Q.checkbox,props.indent?styles$Q.indented:undefined],children:jsxRuntimeExports.jsx(Checkbox$1,{disabled:props.disabled,label:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row"},children:[props.label," ",jsxRuntimeExports.jsx(InfoTip$p,{children:props.infoTip})]}),checked:props.checked,onChange:newCheckedState=>props.onChange(newCheckedState)})});const styles$Q=StyleSheet.create({indented:{marginInlineStart:spacing.large_24}});
1480
+ const{InfoTip: InfoTip$o}=components;class ItemExtrasEditor extends React.Component{shouldShowFinancialCalculatorOptions(){return this.props.financialCalculatorMonthlyPayment||this.props.financialCalculatorTotalAmount||this.props.financialCalculatorTimeToPayOff}render(){const{editingDisabled}=this.props;return jsxRuntimeExports.jsx("div",{className:"perseus-answer-editor",children:jsxRuntimeExports.jsxs("div",{className:"perseus-answer-options",children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show calculator",disabled:editingDisabled,infoTip:"Use the calculator when completing difficult calculations is NOT the intent of the question. DON’T use the calculator when testing the student’s ability to complete different types of computations.",checked:this.props.calculator,onChange:newCheckedState=>{this.props.onChange({calculator:newCheckedState});}}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show financial calculator",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a financial calculator, e.g., for answering financial questions. Once checked, requires at least one of the three options below to be checked.",checked:this.shouldShowFinancialCalculatorOptions(),onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState,financialCalculatorTotalAmount:newCheckedState,financialCalculatorTimeToPayOff:newCheckedState});}}),this.shouldShowFinancialCalculatorOptions()&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include monthly payment",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a monthly payment calculator; e.g., given a loan amount, interest rate, and term, what is the monthly payment?",checked:this.props.financialCalculatorMonthlyPayment,onChange:newCheckedState=>{this.props.onChange({financialCalculatorMonthlyPayment:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include total amount",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a total amount calculator; e.g., given a monthly payment, interest rate, and term, what is the total amount to be paid?",checked:this.props.financialCalculatorTotalAmount,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTotalAmount:newCheckedState});},indent:true}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include time-to-pay-off",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a time to pay off calculator; e.g., given a loan amount, interest rate, and monthly payment, how long will it take to pay off the loan?",checked:this.props.financialCalculatorTimeToPayOff,onChange:newCheckedState=>{this.props.onChange({financialCalculatorTimeToPayOff:newCheckedState});},indent:true})]}),jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show periodic table",disabled:editingDisabled,infoTip:"This provides the student with the ability to view a periodic table of the elements, e.g., for answering chemistry questions.",checked:this.props.periodicTable,onChange:newCheckedState=>{this.props.onChange({periodicTable:newCheckedState,periodicTableWithKey:false});}}),this.props.periodicTable&&jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Include key/legend with periodic table",disabled:editingDisabled,infoTip:"Include a key for HS courses; omit for AP chemistry.",checked:this.props.periodicTableWithKey,onChange:newCheckedState=>{this.props.onChange({periodicTableWithKey:newCheckedState});},indent:true})]})})}constructor(...args){super(...args),this.serialize=()=>{const data={...ItemExtrasEditor.defaultProps};for(const key of ItemExtras){data[key]=!!this.props[key];}return data};}}ItemExtrasEditor.defaultProps={calculator:false,financialCalculatorMonthlyPayment:false,financialCalculatorTotalAmount:false,financialCalculatorTimeToPayOff:false,periodicTable:false,periodicTableWithKey:false};const ItemExtraCheckbox=props=>jsxRuntimeExports.jsx(View,{style:[styles$Q.checkbox,props.indent?styles$Q.indented:undefined],children:jsxRuntimeExports.jsx(Checkbox$1,{disabled:props.disabled,label:jsxRuntimeExports.jsxs(View,{style:{flexDirection:"row"},children:[props.label," ",jsxRuntimeExports.jsx(InfoTip$o,{children:props.infoTip})]}),checked:props.checked,onChange:newCheckedState=>props.onChange(newCheckedState)})});const styles$Q=StyleSheet.create({indented:{marginInlineStart:spacing.large_24}});
1479
1481
 
1480
- class ItemEditor extends React.Component{static getDerivedStateFromProps(props){if(props.question?.content===ItemEditor.prevContent&&props.question?.widgets===ItemEditor.prevWidgets){return null}ItemEditor.prevContent=props.question?.content;ItemEditor.prevWidgets=props.question?.widgets;const parsed=PerseusMarkdown.parse(props.question?.content??"",{});const linterContext={content:props.question?.content,widgets:props.question?.widgets,stack:[]};return {issues:[...props.issues??[],...PerseusLinter.runLinter(parsed,linterContext,false)?.map(linterWarning=>{if(linterWarning.rule==="inaccessible-widget"){return WARNINGS.inaccessibleWidget(linterWarning.metadata?.widgetType??"unknown",linterWarning.metadata?.widgetId??"unknown")}return WARNINGS.genericLinterWarning(linterWarning.rule,linterWarning.message,linterWarning.severity)})??[]]}}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsx(ItemEditorContext.Provider,{value:{question:this.props.question,onEditorChange:this.handleEditorChange},children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-question-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx(IssuesPanel,{apiOptions:this.props.apiOptions,issues:this.state.issues}),jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question"}),jsxRuntimeExports.jsx("fieldset",{disabled:editingDisabled,children:jsxRuntimeExports.jsx(Editor,{ref:this.questionEditor,placeholder:"Type your question here...",className:"perseus-question-editor",imageUploader:this.props.imageUploader,onChange:this.handleEditorChange,apiOptions:this.props.apiOptions,showWordCount:true,widgetIsOpen:this.props.widgetIsOpen,additionalTemplates:this.props.additionalTemplates,...this.props.question},this.props.itemId)})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsxs("div",{id:"problemarea",children:[jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:this.frame,datasetKey:"mobile",datasetValue:isMobile,seamless:true,url:this.props.previewURL},this.props.deviceType)}),jsxRuntimeExports.jsx("div",{id:"hintsarea",className:"hintsarea",style:{display:"none"}})]})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-answer-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question extras"}),jsxRuntimeExports.jsx(ItemExtrasEditor,{ref:this.itemExtrasEditor,onChange:this.handleItemExtrasChange,editingDisabled:editingDisabled,...this.props.answerArea})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell"})]})]})})}constructor(...args){super(...args),this.frame=React.createRef(),this.questionEditor=React.createRef(),this.itemExtrasEditor=React.createRef(),this.state={issues:[]},this.updateProps=(newProps,cb,silent)=>{const props=_(this.props).pick("question","answerArea");this.props.onChange(_(props).extend(newProps),cb,silent);},this.triggerPreviewUpdate=newData=>{this.frame.current?.sendNewData(newData);},this.handleEditorChange=(newProps,cb,silent)=>{const question=_.extend({},this.props.question,newProps);this.updateProps({question},cb,silent);},this.handleItemExtrasChange=newProps=>{const answerArea=_.extend({},this.props.answerArea,newProps);this.updateProps({answerArea},()=>{},true);},this.getSaveWarnings=()=>{return this.questionEditor.current?.getSaveWarnings()},this.serialize=options=>{return {question:this.questionEditor.current?.serialize(options),answerArea:this.itemExtrasEditor.current?.serialize()}};}}ItemEditor.defaultProps={onChange:()=>{},question:{},answerArea:{}};
1482
+ class ItemEditor extends React.Component{static getDerivedStateFromProps(props){if(props.question?.content===ItemEditor.prevContent&&props.question?.widgets===ItemEditor.prevWidgets){return null}ItemEditor.prevContent=props.question?.content;ItemEditor.prevWidgets=props.question?.widgets;const parsed=PerseusMarkdown.parse(props.question?.content??"",{});const linterContext={content:props.question?.content,widgets:props.question?.widgets,stack:[]};const texErrors=detectTexErrors(props.question?.content??"");const texIssues=texErrors.map((error,index)=>WARNINGS.texError(error.math,error.message,index));return {issues:[...props.issues??[],...PerseusLinter.runLinter(parsed,linterContext,false)?.map(linterWarning=>{if(linterWarning.rule==="inaccessible-widget"){return WARNINGS.inaccessibleWidget(linterWarning.metadata?.widgetType??"unknown",linterWarning.metadata?.widgetId??"unknown")}return WARNINGS.genericLinterWarning(linterWarning.rule,linterWarning.message,linterWarning.severity)})??[],...texIssues]}}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsx(ItemEditorContext.Provider,{value:{question:this.props.question,onEditorChange:this.handleEditorChange},children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-question-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx(IssuesPanel,{apiOptions:this.props.apiOptions,issues:this.state.issues}),jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question"}),jsxRuntimeExports.jsx("fieldset",{disabled:editingDisabled,children:jsxRuntimeExports.jsx(Editor,{ref:this.questionEditor,placeholder:"Type your question here...",className:"perseus-question-editor",imageUploader:this.props.imageUploader,onChange:this.handleEditorChange,apiOptions:this.props.apiOptions,showWordCount:true,widgetIsOpen:this.props.widgetIsOpen,additionalTemplates:this.props.additionalTemplates,...this.props.question},this.props.itemId)})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell",children:jsxRuntimeExports.jsx("div",{id:"problemarea",children:jsxRuntimeExports.jsx(DeviceFramer,{deviceType:this.props.deviceType,nochrome:true,children:jsxRuntimeExports.jsx(IframeContentRenderer,{ref:this.frame,datasetKey:"mobile",datasetValue:isMobile,seamless:true,url:this.props.previewURL},this.props.deviceType)})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row perseus-answer-container",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question extras"}),jsxRuntimeExports.jsx(ItemExtrasEditor,{ref:this.itemExtrasEditor,onChange:this.handleItemExtrasChange,editingDisabled:editingDisabled,...this.props.answerArea})]}),jsxRuntimeExports.jsx("div",{className:"perseus-editor-right-cell"})]})]})})}constructor(...args){super(...args),this.frame=React.createRef(),this.questionEditor=React.createRef(),this.itemExtrasEditor=React.createRef(),this.state={issues:[]},this.updateProps=(newProps,cb,silent)=>{const props=_(this.props).pick("question","answerArea");this.props.onChange(_(props).extend(newProps),cb,silent);},this.triggerPreviewUpdate=newData=>{this.frame.current?.sendNewData(newData);},this.handleEditorChange=(newProps,cb,silent)=>{const question=_.extend({},this.props.question,newProps);this.updateProps({question},cb,silent);},this.handleItemExtrasChange=newProps=>{const answerArea=_.extend({},this.props.answerArea,newProps);this.updateProps({answerArea},()=>{},true);},this.getSaveWarnings=()=>{return this.questionEditor.current?.getSaveWarnings()},this.serialize=options=>{return {question:this.questionEditor.current?.serialize(options),answerArea:this.itemExtrasEditor.current?.serialize()}};}}ItemEditor.defaultProps={onChange:()=>{},question:{},answerArea:{}};
1481
1483
 
1482
1484
  const{HUD}=components;class EditorPage extends React.Component{componentDidMount(){this._isMounted=true;this.updateRenderer();}componentDidUpdate(){setTimeout(()=>{this.updateRenderer();});}componentWillUnmount(){this._isMounted=false;}updateRenderer(){const hasEditor=!this.props.developerMode||!this.props.jsonMode;if(!this._isMounted||!hasEditor){return}const touch=this.props.previewDevice==="phone"||this.props.previewDevice==="tablet";const deviceBasedApiOptions={...this.getApiOptions(),customKeypad:touch,isMobile:touch};this.itemEditor.current?.triggerPreviewUpdate({type:"question",data:_({item:this.serialize(),apiOptions:deviceBasedApiOptions,initialHintsVisible:0,device:this.props.previewDevice,linterContext:{contentType:"exercise",highlightLint:this.state.highlightLint,paths:this.props.contentPaths||[]},reviewMode:true,legacyPerseusLint:this.itemEditor.current?.getSaveWarnings()}).extend(_(this.props).pick("problemNum"))});}getApiOptions(){return {...ApiOptions.defaults,...this.props.apiOptions}}getSaveWarnings(){const issues1=this.itemEditor.current?.getSaveWarnings();const issues2=this.hintsEditor.current?.getSaveWarnings();return issues1.concat(issues2)}serialize(options){if(this.props.jsonMode){return this.state.json}return _.extend(this.itemEditor.current?.serialize(options),{hints:this.hintsEditor.current?.serialize(options)})}render(){let className="framework-perseus";const editingDisabled=this.props.apiOptions?.editingDisabled??false;const touch=this.props.previewDevice==="phone"||this.props.previewDevice==="tablet";const deviceBasedApiOptions={...this.getApiOptions(),customKeypad:touch,isMobile:touch};if(deviceBasedApiOptions.isMobile){className+=" "+ClassNames.MOBILE;}return jsxRuntimeExports.jsx(Dependencies.DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsxs("div",{id:"perseus",className:className,children:[jsxRuntimeExports.jsxs("div",{style:{marginBottom:10},children:[this.props.developerMode&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Developer JSON Mode:"," ",jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.jsonMode,disabled:this.props.apiOptions?.editingDisabled,onChange:this.toggleJsonMode})]})," "]}),!this.props.jsonMode&&jsxRuntimeExports.jsx(ViewportResizer,{deviceType:this.props.previewDevice,onViewportSizeChanged:this.props.onPreviewDeviceChange}),!this.props.jsonMode&&jsxRuntimeExports.jsx(HUD,{message:"Style warnings",enabled:this.state.highlightLint,onClick:()=>{this.setState({highlightLint:!this.state.highlightLint});}})]}),this.props.developerMode&&this.props.jsonMode&&jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(JsonEditor,{multiLine:true,value:this.state.json,onChange:this.changeJSON,editingDisabled:editingDisabled})}),(!this.props.developerMode||!this.props.jsonMode)&&jsxRuntimeExports.jsx(ItemEditor,{ref:this.itemEditor,itemId:this.props.itemId,question:this.props.question,answerArea:this.props.answerArea,imageUploader:this.props.imageUploader,onChange:this.handleChange,deviceType:this.props.previewDevice,widgetIsOpen:this.state.widgetsAreOpen,apiOptions:deviceBasedApiOptions,previewURL:this.props.previewURL,issues:this.props.issues,additionalTemplates:this.props.additionalTemplates}),(!this.props.developerMode||!this.props.jsonMode)&&jsxRuntimeExports.jsx(CombinedHintsEditor,{ref:this.hintsEditor,itemId:this.props.itemId,hints:this.props.hints,imageUploader:this.props.imageUploader,onChange:this.handleChange,deviceType:this.props.previewDevice,apiOptions:deviceBasedApiOptions,previewURL:this.props.previewURL,highlightLint:this.state.highlightLint,widgetIsOpen:this.state.widgetsAreOpen})]})})}constructor(props){super(props),this.itemEditor=React.createRef(),this.hintsEditor=React.createRef(),this.toggleJsonMode=()=>{this.setState({json:this.serialize({keepDeletedWidgets:true})},()=>{this.props.onChange({jsonMode:!this.props.jsonMode});});},this.handleChange=(toChange,cb,silent)=>{const newProps=_(this.props).pick("question","hints","answerArea");_(newProps).extend(toChange);this.props.onChange(newProps,cb,silent);},this.changeJSON=newJson=>{this.setState({json:newJson});this.props.onChange(newJson);};this.state={json:_.pick(this.props,"question","answerArea","hints"),gradeMessage:"",wasAnswered:false,highlightLint:true,widgetsAreOpen:this.props.widgetsAreOpen??true};this._isMounted=false;}}EditorPage.defaultProps={developerMode:false,jsonMode:false,onChange:()=>{}};
1483
1485
 
@@ -1487,18 +1489,18 @@ const{TextListEditor: TextListEditor$4}=components;const Categorizer=Categorizer
1487
1489
 
1488
1490
  class BlurInput extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState({value:nextProps.value});}focus(){this.input.current?.focus();}render(){return jsxRuntimeExports.jsx("input",{ref:this.input,className:this.props.className,style:this.props.style,type:"text",value:this.state.value,onChange:this.handleChange,onBlur:this.handleBlur})}constructor(props){super(props),this.input=React.createRef(),this.handleChange=e=>{this.setState({value:e.target.value});},this.handleBlur=e=>{this.props.onChange(e.target.value);};this.state={value:this.props.value};}}
1489
1491
 
1490
- const{InfoTip: InfoTip$o}=components;const DEFAULT_WIDTH=400;const DEFAULT_HEIGHT=400;let PairEditor$1 = class PairEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("fieldset",{className:"pair-editor",children:[jsxRuntimeExports.jsxs("label",{children:["Name:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.name,onChange:this.change("name")})]}),jsxRuntimeExports.jsxs("label",{children:[" ","Value:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.value,onChange:this.change("value")})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairEditor$1.propTypes={...Changeable.propTypes,name:PropTypes.string,value:PropTypes.string};PairEditor$1.defaultProps={name:"",value:""};let PairsEditor$1 = class PairsEditor extends React.Component{render(){const editors=_.map(this.props.pairs,(pair,i)=>{return jsxRuntimeExports.jsx(PairEditor$1,{name:pair.name,value:pair.value,onChange:this.handlePairChange.bind(this,i)},i)});return jsxRuntimeExports.jsx("div",{children:editors})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handlePairChange=(pairIndex,pair)=>{const pairs=this.props.pairs.slice();pairs[pairIndex]=pair;const lastPair=pairs[pairs.length-1];if(lastPair.name&&lastPair.value){pairs.push({name:"",value:""});}this.change("pairs",pairs);},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairsEditor$1.propTypes={...Changeable.propTypes,pairs:PropTypes.arrayOf(PropTypes.shape({name:PropTypes.string,value:PropTypes.string})).isRequired};const KA_PROGRAM_URL=/khanacademy\.org\/computer-programming\/[^\/]+\/(\d+)/;function isolateProgramID(programUrl){const match=KA_PROGRAM_URL.exec(programUrl);if(match){programUrl=match[1];}return programUrl}class CSProgramEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Url or Program ID:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.programID,onChange:this._handleProgramIDChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Editor",checked:this.props.showEditor,onChange:value=>{this.props.onChange({showEditor:value});}}),jsxRuntimeExports.jsx(InfoTip$o,{children:'If you show the editor, you should use the "full-width" alignment to make room for the width of the editor.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Buttons",checked:this.props.showButtons,onChange:value=>{this.props.onChange({showButtons:value});}}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Settings:",jsxRuntimeExports.jsx(PairsEditor$1,{name:"settings",pairs:this.props.settings,onChange:this._handleSettingsChange}),jsxRuntimeExports.jsxs(InfoTip$o,{children:["Settings that you add here are available to the program as an object returned by ",jsxRuntimeExports.jsx("code",{children:"Program.settings()"})]})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this._handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this._handleProgramIDChange=programID=>{programID=isolateProgramID(programID);const{isDevServer,InitialRequestUrl}=Dependencies.getDependencies();const host=isDevServer?InitialRequestUrl.origin:"https://www.khanacademy.org";const baseUrl=`${host}/api/internal/scratchpads/${programID}`;$.getJSON(baseUrl).done(programInfo=>{const programType=programInfo.userAuthoredContentType;this.change({width:programInfo.width,height:programInfo.height,programID:programID,programType:programType});}).fail((jqxhr,textStatus,error)=>{Log.error("Error retrieving scratchpad info for program ID ",Errors.TransientService,{cause:error,loggedMetadata:{textStatus,programID}});this.change({width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,programID:programID,programType:null});});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CSProgramEditor.propTypes={...Changeable.propTypes};CSProgramEditor.widgetName="cs-program";CSProgramEditor.defaultProps=csProgramLogic.defaultWidgetOptions;
1492
+ const{InfoTip: InfoTip$n}=components;const DEFAULT_WIDTH=400;const DEFAULT_HEIGHT=400;let PairEditor$1 = class PairEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("fieldset",{className:"pair-editor",children:[jsxRuntimeExports.jsxs("label",{children:["Name:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.name,onChange:this.change("name")})]}),jsxRuntimeExports.jsxs("label",{children:[" ","Value:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.value,onChange:this.change("value")})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairEditor$1.propTypes={...Changeable.propTypes,name:PropTypes.string,value:PropTypes.string};PairEditor$1.defaultProps={name:"",value:""};let PairsEditor$1 = class PairsEditor extends React.Component{render(){const editors=_.map(this.props.pairs,(pair,i)=>{return jsxRuntimeExports.jsx(PairEditor$1,{name:pair.name,value:pair.value,onChange:this.handlePairChange.bind(this,i)},i)});return jsxRuntimeExports.jsx("div",{children:editors})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handlePairChange=(pairIndex,pair)=>{const pairs=this.props.pairs.slice();pairs[pairIndex]=pair;const lastPair=pairs[pairs.length-1];if(lastPair.name&&lastPair.value){pairs.push({name:"",value:""});}this.change("pairs",pairs);},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}};PairsEditor$1.propTypes={...Changeable.propTypes,pairs:PropTypes.arrayOf(PropTypes.shape({name:PropTypes.string,value:PropTypes.string})).isRequired};const KA_PROGRAM_URL=/khanacademy\.org\/computer-programming\/[^\/]+\/(\d+)/;function isolateProgramID(programUrl){const match=KA_PROGRAM_URL.exec(programUrl);if(match){programUrl=match[1];}return programUrl}class CSProgramEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Url or Program ID:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.programID,onChange:this._handleProgramIDChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Editor",checked:this.props.showEditor,onChange:value=>{this.props.onChange({showEditor:value});}}),jsxRuntimeExports.jsx(InfoTip$n,{children:'If you show the editor, you should use the "full-width" alignment to make room for the width of the editor.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Show Buttons",checked:this.props.showButtons,onChange:value=>{this.props.onChange({showButtons:value});}}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Settings:",jsxRuntimeExports.jsx(PairsEditor$1,{name:"settings",pairs:this.props.settings,onChange:this._handleSettingsChange}),jsxRuntimeExports.jsxs(InfoTip$n,{children:["Settings that you add here are available to the program as an object returned by ",jsxRuntimeExports.jsx("code",{children:"Program.settings()"})]})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this._handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this._handleProgramIDChange=programID=>{programID=isolateProgramID(programID);const{isDevServer,InitialRequestUrl}=Dependencies.getDependencies();const host=isDevServer?InitialRequestUrl.origin:"https://www.khanacademy.org";const baseUrl=`${host}/api/internal/scratchpads/${programID}`;$.getJSON(baseUrl).done(programInfo=>{const programType=programInfo.userAuthoredContentType;this.change({width:programInfo.width,height:programInfo.height,programID:programID,programType:programType});}).fail((jqxhr,textStatus,error)=>{Log.error("Error retrieving scratchpad info for program ID ",Errors.TransientService,{cause:error,loggedMetadata:{textStatus,programID}});this.change({width:DEFAULT_WIDTH,height:DEFAULT_HEIGHT,programID:programID,programType:null});});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}CSProgramEditor.propTypes={...Changeable.propTypes};CSProgramEditor.widgetName="cs-program";CSProgramEditor.defaultProps=csProgramLogic.defaultWidgetOptions;
1491
1493
 
1492
1494
  const{TextInput: TextInput$7}=components;class DefinitionEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-definition-editor",children:[jsxRuntimeExports.jsx("a",{href:"https://docs.google.com/document/d/1udaPef4imOfTMhmLDlWq4SM0mxL0r3YHFZE-5J1uGfo",target:"_blank",rel:"noreferrer",children:"Definition style guide"}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Word to be defined:"," ",jsxRuntimeExports.jsx(TextInput$7,{value:this.props.togglePrompt,onChange:this.change("togglePrompt"),placeholder:"define me"})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.definition,widgetEnabled:false,placeholder:"definition goes here",onChange:props=>{const newProps={};if(_.has(props,"content")){newProps.definition=props.content;}this.change(newProps);}})})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DefinitionEditor.propTypes={...Changeable.propTypes,togglePrompt:PropTypes.string,definition:PropTypes.string,apiOptions:PropTypes.any};DefinitionEditor.widgetName="definition";DefinitionEditor.defaultProps=definitionLogic.defaultWidgetOptions;
1493
1495
 
1494
1496
  class DeprecatedStandinEditor extends React.Component{serialize(){return EditorJsonify.serialize.call(this)}render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("p",{children:"This widget has been deprecated and removed"}),jsxRuntimeExports.jsx("p",{children:"Learners will see a message and they will not be graded on this part. Please replace this widget with a supported one."})]})}}DeprecatedStandinEditor.widgetName="deprecated-standin";
1495
1497
 
1496
- const{InfoTip: InfoTip$n}=components;class DropdownEditor extends React.Component{render(){const dropdownGroupName=_.uniqueId("perseus_dropdown_");const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-dropdown",children:[jsxRuntimeExports.jsxs("div",{className:"dropdown-info",children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Dropdown"}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsxs("p",{children:["The drop down is useful for making inequalities in a custom format. We normally use the symbols ","<",","," ",">",', ≤, ≥ (in that order) which you can copy into the choices. When possible, use the "multiple choice" answer type instead.']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Visible label",jsxRuntimeExports.jsx(TextField,{value:this.props.visibleLabel,onChange:this.onVisibleLabelChange})]}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsx("p",{children:"Optional visible label"})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Aria label",jsxRuntimeExports.jsx(TextField,{value:this.props.ariaLabel,onChange:this.onAriaLabelChange,type:"text"})]}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsxs("p",{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writing accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})," ",'If left blank, the value will default to "Select an answer".']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Placeholder",jsxRuntimeExports.jsx(TextField,{value:this.props.placeholder,onChange:this.onPlaceholderChange,placeholder:"Placeholder value"})]}),jsxRuntimeExports.jsx(InfoTip$n,{children:jsxRuntimeExports.jsx("p",{children:"This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."})})]}),jsxRuntimeExports.jsx("div",{className:"clearfix"}),jsxRuntimeExports.jsx(LabelMedium,{children:"Choices"}),jsxRuntimeExports.jsx("ul",{className:"dropdown-choices",children:this.props.choices.map((choice,i)=>{const choiceBackgroundColor=choice.correct?semanticColor.core.background.success.subtle:semanticColor.core.background.critical.subtle;return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("div",{className:"dropdown-choice",children:[jsxRuntimeExports.jsx("input",{type:"radio",ref:"radio"+i,name:dropdownGroupName,checked:choice.correct,onChange:()=>this.onCorrectChange(i)}),jsxRuntimeExports.jsx(TextField,{value:choice.content,ref:"editor"+i,"aria-label":`Choice ${i+1} content`,disabled:editingDisabled,style:{backgroundColor:choiceBackgroundColor},onChange:newContent=>this.onContentChange(i,newContent)}),jsxRuntimeExports.jsx(IconButton,{icon:trashIcon,"aria-label":"Delete choice",disabled:editingDisabled,kind:"tertiary",size:"small",onClick:()=>this.removeChoice(i)})]})},""+i)},this)}),jsxRuntimeExports.jsx("div",{className:"add-choice-container",children:jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:editingDisabled,onClick:this.addChoice,startIcon:plusIcon,children:"Add a choice"})})]})}constructor(...args){super(...args),this.onVisibleLabelChange=visibleLabel=>{this.props.onChange({visibleLabel});},this.onAriaLabelChange=ariaLabel=>{this.props.onChange({ariaLabel});},this.onPlaceholderChange=placeholder=>{this.props.onChange({placeholder});},this.onCorrectChange=choiceIndex=>{const choices=_.map(this.props.choices,function(choice,i){return _.extend({},choice,{correct:i===choiceIndex})});this.props.onChange({choices:choices});},this.onContentChange=(choiceIndex,newContent)=>{const choices=this.props.choices.slice();const choice=_.clone(choices[choiceIndex]);choice.content=newContent;choices[choiceIndex]=choice;this.props.onChange({choices:choices});},this.addChoice=()=>{const choices=this.props.choices;const blankChoice={content:"",correct:false};this.props.onChange({choices:choices.concat([blankChoice])},this.focus.bind(this,choices.length));},this.removeChoice=choiceIndex=>{const choices=_(this.props.choices).clone();choices.splice(choiceIndex,1);this.props.onChange({choices:choices});},this.focus=i=>{ReactDOM.findDOMNode(this.refs["editor"+i]).focus();return true},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DropdownEditor.propTypes={choices:PropTypes.arrayOf(PropTypes.shape({content:PropTypes.string,correct:PropTypes.bool})),placeholder:PropTypes.string};DropdownEditor.widgetName="dropdown";DropdownEditor.defaultProps=dropdownLogic.defaultWidgetOptions;
1498
+ const{InfoTip: InfoTip$m}=components;class DropdownEditor extends React.Component{render(){const dropdownGroupName=_.uniqueId("perseus_dropdown_");const editingDisabled=this.props.apiOptions?.editingDisabled??false;return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-dropdown",children:[jsxRuntimeExports.jsxs("div",{className:"dropdown-info",children:[jsxRuntimeExports.jsx(LabelLarge,{children:"Dropdown"}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsxs("p",{children:["The drop down is useful for making inequalities in a custom format. We normally use the symbols ","<",","," ",">",', ≤, ≥ (in that order) which you can copy into the choices. When possible, use the "multiple choice" answer type instead.']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Visible label",jsxRuntimeExports.jsx(TextField,{value:this.props.visibleLabel,onChange:this.onVisibleLabelChange})]}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsx("p",{children:"Optional visible label"})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Aria label",jsxRuntimeExports.jsx(TextField,{value:this.props.ariaLabel,onChange:this.onAriaLabelChange,type:"text"})]}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsxs("p",{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writing accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})," ",'If left blank, the value will default to "Select an answer".']})})]}),jsxRuntimeExports.jsxs("div",{className:"dropdown-field",children:[jsxRuntimeExports.jsxs(LabelMedium,{children:["Placeholder",jsxRuntimeExports.jsx(TextField,{value:this.props.placeholder,onChange:this.onPlaceholderChange,placeholder:"Placeholder value"})]}),jsxRuntimeExports.jsx(InfoTip$m,{children:jsxRuntimeExports.jsx("p",{children:"This value will appear as the drop down default. It should give the user some indication of the values available in the drop down itself, e.g., Yes/No/Maybe."})})]}),jsxRuntimeExports.jsx("div",{className:"clearfix"}),jsxRuntimeExports.jsx(LabelMedium,{children:"Choices"}),jsxRuntimeExports.jsx("ul",{className:"dropdown-choices",children:this.props.choices.map((choice,i)=>{const choiceBackgroundColor=choice.correct?semanticColor.core.background.success.subtle:semanticColor.core.background.critical.subtle;return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("div",{className:"dropdown-choice",children:[jsxRuntimeExports.jsx("input",{type:"radio",ref:"radio"+i,name:dropdownGroupName,checked:choice.correct,onChange:()=>this.onCorrectChange(i)}),jsxRuntimeExports.jsx(TextField,{value:choice.content,ref:"editor"+i,"aria-label":`Choice ${i+1} content`,disabled:editingDisabled,style:{backgroundColor:choiceBackgroundColor},onChange:newContent=>this.onContentChange(i,newContent)}),jsxRuntimeExports.jsx(IconButton,{icon:trashIcon,"aria-label":"Delete choice",disabled:editingDisabled,kind:"tertiary",size:"small",onClick:()=>this.removeChoice(i)})]})},""+i)},this)}),jsxRuntimeExports.jsx("div",{className:"add-choice-container",children:jsxRuntimeExports.jsx(Button,{kind:"secondary",disabled:editingDisabled,onClick:this.addChoice,startIcon:plusIcon,children:"Add a choice"})})]})}constructor(...args){super(...args),this.onVisibleLabelChange=visibleLabel=>{this.props.onChange({visibleLabel});},this.onAriaLabelChange=ariaLabel=>{this.props.onChange({ariaLabel});},this.onPlaceholderChange=placeholder=>{this.props.onChange({placeholder});},this.onCorrectChange=choiceIndex=>{const choices=_.map(this.props.choices,function(choice,i){return _.extend({},choice,{correct:i===choiceIndex})});this.props.onChange({choices:choices});},this.onContentChange=(choiceIndex,newContent)=>{const choices=this.props.choices.slice();const choice=_.clone(choices[choiceIndex]);choice.content=newContent;choices[choiceIndex]=choice;this.props.onChange({choices:choices});},this.addChoice=()=>{const choices=this.props.choices;const blankChoice={content:"",correct:false};this.props.onChange({choices:choices.concat([blankChoice])},this.focus.bind(this,choices.length));},this.removeChoice=choiceIndex=>{const choices=_(this.props.choices).clone();choices.splice(choiceIndex,1);this.props.onChange({choices:choices});},this.focus=i=>{ReactDOM.findDOMNode(this.refs["editor"+i]).focus();return true},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}DropdownEditor.propTypes={choices:PropTypes.arrayOf(PropTypes.shape({content:PropTypes.string,correct:PropTypes.bool})),placeholder:PropTypes.string};DropdownEditor.widgetName="dropdown";DropdownEditor.defaultProps=dropdownLogic.defaultWidgetOptions;
1497
1499
 
1498
1500
  const{TextInput: TextInput$6}=components;class ExplanationEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-explanation-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Prompt to show explanation:"," ",jsxRuntimeExports.jsx(TextInput$6,{value:this.props.showPrompt,onChange:this.change("showPrompt")})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Prompt to hide explanation:"," ",jsxRuntimeExports.jsx(TextInput$6,{value:this.props.hidePrompt,onChange:this.change("hidePrompt")})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:this.props.explanation,widgets:this.props.widgets,widgetEnabled:true,immutableWidgets:false,onChange:props=>{const newProps={};if(_.has(props,"content")){newProps.explanation=props.content;}if(_.has(props,"widgets")){newProps.widgets=props.widgets;}this.change(newProps);}})})]})}constructor(...args){super(...args),this.state={},this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}ExplanationEditor.propTypes={...Changeable.propTypes,showPrompt:PropTypes.string,hidePrompt:PropTypes.string,explanation:PropTypes.string,widgets:PropTypes.object,apiOptions:PropTypes.any};ExplanationEditor.widgetName="explanation";ExplanationEditor.defaultProps=explanationLogic.defaultWidgetOptions;
1499
1501
 
1500
- const{ButtonGroup: ButtonGroup$7,InfoTip: InfoTip$m}=components;const buttonSetsList=["basic","trig","prealgebra","logarithms","scientific","basic relations","advanced relations"];class ExpressionEditor extends React.Component{serialize(){const{answerForms,buttonSets,functions,times,visibleLabel,ariaLabel}=this.props;return {answerForms,buttonSets,functions,times,visibleLabel,ariaLabel,extraKeys:deriveExtraKeys(this.props)}}updateAnswerForm(index,answerFormProps){const answerForms=this.props.answerForms.slice();answerForms[index]=answerFormProps;const{extraKeys:_,...restProps}=this.props;const extraKeys=deriveExtraKeys({...restProps,answerForms});this.props.onChange({answerForms,extraKeys});}changeSimplify(index,simplify){const answerForm={...this.props.answerForms[index],simplify};this.updateAnswerForm(index,answerForm);}changeForm(index,form){const answerForm={...this.props.answerForms[index],form};this.updateAnswerForm(index,answerForm);}changeConsidered(index,considered){const answerForm={...this.props.answerForms[index],considered};this.updateAnswerForm(index,answerForm);}changeTimes(times){this.props.onChange({times:times});}render(){const answerOptions=this.props.answerForms.map((ans,index)=>{const expressionProps={times:this.props.times,functions:this.props.functions,buttonSets:this.props.buttonSets,buttonsVisible:"focused",userInput:ans.value,handleUserInput:input=>this.changeExpressionWidget(index,input),trackInteraction:()=>{},widgetId:this.props.widgetId+"-"+ans.key,visibleLabel:this.props.visibleLabel,ariaLabel:this.props.ariaLabel};return jsxRuntimeExports.jsx(AnswerOption,{considered:ans.considered,expressionProps:expressionProps,form:ans.form,simplify:ans.simplify,onDelete:()=>this.handleRemoveForm(index),onChangeSimplify:simplify=>this.changeSimplify(index,simplify),onChangeForm:form=>this.changeForm(index,form),onChangeConsidered:considered=>this.changeConsidered(index,considered)},ans.key)});const buttonSetChoices=buttonSetsList.map(name=>{const isBasic=name==="basic";const checked=this.props.buttonSets.includes(name)||isBasic;return jsxRuntimeExports.jsx(Checkbox$1,{label:name,checked:checked,disabled:isBasic,onChange:()=>this.handleButtonSet(name)},name)});buttonSetChoices.unshift(jsxRuntimeExports.jsx(Checkbox$1,{label:"show ÷ button",checked:this.props.buttonSets.includes("basic+div"),onChange:this.handleToggleDiv},"show ÷ button"));return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Global Options"}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Visible label",jsxRuntimeExports.jsx(InfoTip$m,{children:"Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."})]}),value:this.props.visibleLabel||"",onChange:this.handleVisibleLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Aria label",jsxRuntimeExports.jsxs(InfoTip$m,{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})]})]}),value:this.props.ariaLabel||"",onChange:this.handleAriaLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Function variables",jsxRuntimeExports.jsx(InfoTip$m,{children:'Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means "f of x" and not "f times x".'})]}),value:this.state.functionsInternal,onChange:this.handleFunctions})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Use × instead of ⋅ for multiplication",jsxRuntimeExports.jsx(InfoTip$m,{children:"For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."})]}),checked:this.props.times,onChange:newCheckedState=>{this.changeTimes(newCheckedState);}})}),jsxRuntimeExports.jsxs("div",{className:css(styles$O.paddedY),children:[jsxRuntimeExports.jsx(HeadingXSmall,{children:"Button Sets"}),buttonSetChoices]}),jsxRuntimeExports.jsx(HeadingSmall,{children:"Answers"}),jsxRuntimeExports.jsx(Caption,{style:styles$O.answersSubtitle,children:"student responses area matched against these from top to bottom"}),jsxRuntimeExports.jsx(View,{style:{gap:spacing.xSmall_8},children:answerOptions}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.newAnswer,children:"Add new answer"})]})}constructor(props){super(props),this.getSaveWarnings=()=>{const issues=[];if(this.props.answerForms.length===0){issues.push("No answers specified");}else {const hasCorrect=this.props.answerForms.some(form=>{return form.considered==="correct"});if(!hasCorrect){issues.push("No correct answer specified");}_(this.props.answerForms).each((form,ix)=>{if(this.props.value===""){issues.push(`Answer ${ix+1} is empty`);}else {const expression=KAS.parse(form.value,{functions:this.props.functions});if(!expression.parsed){issues.push(`Couldn't parse ${form.value}`);}else if(form.simplify&&!expression.expr.isSimplified()){issues.push(`${form.value} isn't simplified, but is required" +
1501
- " to be`);}}});}return issues},this.newAnswer=()=>{const answerForms=this.props.answerForms.slice();const newKey=crypto.randomUUID();const newAnswerForm={considered:"correct",form:false,key:`${newKey}`,simplify:false,value:""};answerForms.push(newAnswerForm);this.props.onChange({answerForms});},this.handleRemoveForm=i=>{const updatedAnswerForms=this.props.answerForms.slice();updatedAnswerForms.splice(i,1);this.props.onChange({answerForms:updatedAnswerForms});},this.handleButtonSet=changingName=>{const buttonSetNames=buttonSetsList;const buttonSets=buttonSetNames.filter(set=>{return this.props.buttonSets.includes(set)!==(set===changingName)});this.props.onChange({buttonSets});},this.handleToggleDiv=()=>{let keep;let remove;if(this.props.buttonSets.includes("basic+div")){keep="basic";remove="basic+div";}else {keep="basic+div";remove="basic";}const buttonSets=this.props.buttonSets.filter(set=>set!==remove).concat(keep);this.props.onChange({buttonSets});},this.handleTexInsert=str=>{this.refs.expression.insert(str);},this.handleFunctions=value=>{this.setState({functionsInternal:value});const newProps={};newProps.functions=value.split(/[ ,]+/).filter(isTruthy);this.props.onChange(newProps);},this.handleVisibleLabel=visibleLabel=>{this.props.onChange({visibleLabel});},this.handleAriaLabel=ariaLabel=>{this.props.onChange({ariaLabel});},this.changeExpressionWidget=(index,input)=>{const answerForm={...this.props.answerForms[index],value:input};this.updateAnswerForm(index,answerForm);};this.state={functionsInternal:this.props.functions.join(" ")};}}ExpressionEditor.widgetName="expression";ExpressionEditor.defaultProps=expressionLogic.defaultWidgetOptions;const findNextIn=function(arr,val){let ix=arr.indexOf(val);ix=(ix+1)%arr.length;return arr[ix]};class AnswerOption extends React.Component{render(){const removeButton=this.state.deleteFocused?jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleImSure,actionType:"destructive",children:"I'm sure!"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleCancelDelete,kind:"secondary",children:"Cancel"})]}):jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleDelete,actionType:"destructive",kind:"tertiary",style:styles$O.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:css(styles$O.answerOption),children:[jsxRuntimeExports.jsx(ButtonGroup$7,{onChange:this.toggleConsidered,allowEmpty:false,value:this.props.considered,selectedButtonStyle:consideredButtonStyles[this.props.considered],buttons:PerseusExpressionAnswerFormConsidered.map(c=>({value:c,content:c,title:`This answer will be considered ${c}`}))}),jsxRuntimeExports.jsx(Expression,{...this.props.expressionProps}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY,styles$O.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must have the same form.",jsxRuntimeExports.jsx(InfoTip$m,{children:"The student's answer must be in the same form. Commutativity and excess negative signs are ignored."})]}),checked:this.props.form,onChange:this.props.onChangeForm})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY,styles$O.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must be fully expanded and simplified.",jsxRuntimeExports.jsx(InfoTip$m,{children:'The student\'s answer must be fully expanded and simplified. Answering this equation (x^2+2x+1) with this factored equation (x+1)^2 will render this response "Your answer is not fully expanded and simplified."'})]}),checked:this.props.simplify,onChange:this.props.onChangeSimplify})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.buttonRow,styles$O.paddedY),children:removeButton})]})}constructor(...args){super(...args),this.state={deleteFocused:false},this.handleImSure=()=>{this.props.onDelete();this.handleCancelDelete();},this.handleCancelDelete=()=>{this.setState({deleteFocused:false});},this.handleDelete=()=>{this.setState({deleteFocused:true});},this.toggleConsidered=()=>{const newVal=findNextIn(PerseusExpressionAnswerFormConsidered,this.props.considered);this.props.onChangeConsidered(newVal);};}}const styles$O=StyleSheet.create({paddedX:{paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8},paddedY:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},answersSubtitle:{fontStyle:"italic"},answerOption:{border:"1px solid #ddd",borderRadius:"3px",display:"flex",flexDirection:"column"},answerStatusWrong:{backgroundColor:color.fadedRed16},answerStatusCorrect:{backgroundColor:color.fadedGreen16},answerStatusUngraded:{backgroundColor:color.fadedBlue16},buttonRow:{display:"flex"},deleteButton:{paddingInline:sizing.size_160}});const consideredButtonStyles={wrong:styles$O.answerStatusWrong,correct:styles$O.answerStatusCorrect,ungraded:styles$O.answerStatusUngraded};
1502
+ const{ButtonGroup: ButtonGroup$7,InfoTip: InfoTip$l}=components;const buttonSetsList=["basic","trig","prealgebra","logarithms","scientific","basic relations","advanced relations"];class ExpressionEditor extends React.Component{serialize(){const{answerForms,buttonSets,functions,times,visibleLabel,ariaLabel}=this.props;return {answerForms,buttonSets,functions,times,visibleLabel,ariaLabel,extraKeys:deriveExtraKeys(this.props)}}updateAnswerForm(index,answerFormProps){const answerForms=this.props.answerForms.slice();answerForms[index]=answerFormProps;const{extraKeys:_,...restProps}=this.props;const extraKeys=deriveExtraKeys({...restProps,answerForms});this.props.onChange({answerForms,extraKeys});}changeSimplify(index,simplify){const answerForm={...this.props.answerForms[index],simplify};this.updateAnswerForm(index,answerForm);}changeForm(index,form){const answerForm={...this.props.answerForms[index],form};this.updateAnswerForm(index,answerForm);}changeConsidered(index,considered){const answerForm={...this.props.answerForms[index],considered};this.updateAnswerForm(index,answerForm);}changeTimes(times){this.props.onChange({times:times});}render(){const answerOptions=this.props.answerForms.map((ans,index)=>{const expressionProps={times:this.props.times,functions:this.props.functions,buttonSets:this.props.buttonSets,buttonsVisible:"focused",userInput:ans.value,handleUserInput:input=>this.changeExpressionWidget(index,input),trackInteraction:()=>{},widgetId:this.props.widgetId+"-"+ans.key,visibleLabel:this.props.visibleLabel,ariaLabel:this.props.ariaLabel};return jsxRuntimeExports.jsx(AnswerOption,{considered:ans.considered,expressionProps:expressionProps,form:ans.form,simplify:ans.simplify,onDelete:()=>this.handleRemoveForm(index),onChangeSimplify:simplify=>this.changeSimplify(index,simplify),onChangeForm:form=>this.changeForm(index,form),onChangeConsidered:considered=>this.changeConsidered(index,considered)},ans.key)});const buttonSetChoices=buttonSetsList.map(name=>{const isBasic=name==="basic";const checked=this.props.buttonSets.includes(name)||isBasic;return jsxRuntimeExports.jsx(Checkbox$1,{label:name,checked:checked,disabled:isBasic,onChange:()=>this.handleButtonSet(name)},name)});buttonSetChoices.unshift(jsxRuntimeExports.jsx(Checkbox$1,{label:"show ÷ button",checked:this.props.buttonSets.includes("basic+div"),onChange:this.handleToggleDiv},"show ÷ button"));return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Global Options"}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Visible label",jsxRuntimeExports.jsx(InfoTip$l,{children:"Optional visible text; strongly encouraged to help learners using dictation software, but can be omitted if the surrounding content provides enough context."})]}),value:this.props.visibleLabel||"",onChange:this.handleVisibleLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Aria label",jsxRuntimeExports.jsxs(InfoTip$l,{children:["Label text that's read by screen readers. Highly recommend adding a label here to ensure your exercise is accessible. For more information on writting accessible labels, please see"," ",jsxRuntimeExports.jsx("a",{href:"https://www.w3.org/WAI/tips/designing/#ensure-that-form-elements-include-clearly-associated-labels",target:"_blank",rel:"noreferrer",children:"this article."})]})]}),value:this.props.ariaLabel||"",onChange:this.handleAriaLabel})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(LabeledTextField,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Function variables",jsxRuntimeExports.jsx(InfoTip$l,{children:'Single-letter variables listed here will be interpreted as functions. This let us know that f(x) means "f of x" and not "f times x".'})]}),value:this.state.functionsInternal,onChange:this.handleFunctions})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Use × instead of ⋅ for multiplication",jsxRuntimeExports.jsx(InfoTip$l,{children:"For pre-algebra problems this option displays multiplication as \\times instead of \\cdot in both the rendered output and the acceptable formats examples."})]}),checked:this.props.times,onChange:newCheckedState=>{this.changeTimes(newCheckedState);}})}),jsxRuntimeExports.jsxs("div",{className:css(styles$O.paddedY),children:[jsxRuntimeExports.jsx(HeadingXSmall,{children:"Button Sets"}),buttonSetChoices]}),jsxRuntimeExports.jsx(HeadingSmall,{children:"Answers"}),jsxRuntimeExports.jsx(Caption,{style:styles$O.answersSubtitle,children:"student responses area matched against these from top to bottom"}),jsxRuntimeExports.jsx(View,{style:{gap:spacing.xSmall_8},children:answerOptions}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.newAnswer,children:"Add new answer"})]})}constructor(props){super(props),this.getSaveWarnings=()=>{const issues=[];if(this.props.answerForms.length===0){issues.push("No answers specified");}else {const hasCorrect=this.props.answerForms.some(form=>{return form.considered==="correct"});if(!hasCorrect){issues.push("No correct answer specified");}_(this.props.answerForms).each((form,ix)=>{if(this.props.value===""){issues.push(`Answer ${ix+1} is empty`);}else {const expression=KAS.parse(form.value,{functions:this.props.functions});if(!expression.parsed){issues.push(`Couldn't parse ${form.value}`);}else if(form.simplify&&!expression.expr.isSimplified()){issues.push(`${form.value} isn't simplified, but is required" +
1503
+ " to be`);}}});}return issues},this.newAnswer=()=>{const answerForms=this.props.answerForms.slice();const newKey=crypto.randomUUID();const newAnswerForm={considered:"correct",form:false,key:`${newKey}`,simplify:false,value:""};answerForms.push(newAnswerForm);this.props.onChange({answerForms});},this.handleRemoveForm=i=>{const updatedAnswerForms=this.props.answerForms.slice();updatedAnswerForms.splice(i,1);this.props.onChange({answerForms:updatedAnswerForms});},this.handleButtonSet=changingName=>{const buttonSetNames=buttonSetsList;const buttonSets=buttonSetNames.filter(set=>{return this.props.buttonSets.includes(set)!==(set===changingName)});this.props.onChange({buttonSets});},this.handleToggleDiv=()=>{let keep;let remove;if(this.props.buttonSets.includes("basic+div")){keep="basic";remove="basic+div";}else {keep="basic+div";remove="basic";}const buttonSets=this.props.buttonSets.filter(set=>set!==remove).concat(keep);this.props.onChange({buttonSets});},this.handleTexInsert=str=>{this.refs.expression.insert(str);},this.handleFunctions=value=>{this.setState({functionsInternal:value});const newProps={};newProps.functions=value.split(/[ ,]+/).filter(isTruthy);this.props.onChange(newProps);},this.handleVisibleLabel=visibleLabel=>{this.props.onChange({visibleLabel});},this.handleAriaLabel=ariaLabel=>{this.props.onChange({ariaLabel});},this.changeExpressionWidget=(index,input)=>{const answerForm={...this.props.answerForms[index],value:input};this.updateAnswerForm(index,answerForm);};this.state={functionsInternal:this.props.functions.join(" ")};}}ExpressionEditor.widgetName="expression";ExpressionEditor.defaultProps=expressionLogic.defaultWidgetOptions;const findNextIn=function(arr,val){let ix=arr.indexOf(val);ix=(ix+1)%arr.length;return arr[ix]};class AnswerOption extends React.Component{render(){const removeButton=this.state.deleteFocused?jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleImSure,actionType:"destructive",children:"I'm sure!"}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleCancelDelete,kind:"secondary",children:"Cancel"})]}):jsxRuntimeExports.jsx(Button,{size:"small",onClick:this.handleDelete,actionType:"destructive",kind:"tertiary",style:styles$O.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:css(styles$O.answerOption),children:[jsxRuntimeExports.jsx(ButtonGroup$7,{onChange:this.toggleConsidered,allowEmpty:false,value:this.props.considered,selectedButtonStyle:consideredButtonStyles[this.props.considered],buttons:PerseusExpressionAnswerFormConsidered.map(c=>({value:c,content:c,title:`This answer will be considered ${c}`}))}),jsxRuntimeExports.jsx(Expression,{...this.props.expressionProps}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY,styles$O.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must have the same form.",jsxRuntimeExports.jsx(InfoTip$l,{children:"The student's answer must be in the same form. Commutativity and excess negative signs are ignored."})]}),checked:this.props.form,onChange:this.props.onChangeForm})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.paddedY,styles$O.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must be fully expanded and simplified.",jsxRuntimeExports.jsx(InfoTip$l,{children:'The student\'s answer must be fully expanded and simplified. Answering this equation (x^2+2x+1) with this factored equation (x+1)^2 will render this response "Your answer is not fully expanded and simplified."'})]}),checked:this.props.simplify,onChange:this.props.onChangeSimplify})}),jsxRuntimeExports.jsx("div",{className:css(styles$O.buttonRow,styles$O.paddedY),children:removeButton})]})}constructor(...args){super(...args),this.state={deleteFocused:false},this.handleImSure=()=>{this.props.onDelete();this.handleCancelDelete();},this.handleCancelDelete=()=>{this.setState({deleteFocused:false});},this.handleDelete=()=>{this.setState({deleteFocused:true});},this.toggleConsidered=()=>{const newVal=findNextIn(PerseusExpressionAnswerFormConsidered,this.props.considered);this.props.onChangeConsidered(newVal);};}}const styles$O=StyleSheet.create({paddedX:{paddingLeft:spacing.xSmall_8,paddingRight:spacing.xSmall_8},paddedY:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},answersSubtitle:{fontStyle:"italic"},answerOption:{border:"1px solid #ddd",borderRadius:"3px",display:"flex",flexDirection:"column"},answerStatusWrong:{backgroundColor:color.fadedRed16},answerStatusCorrect:{backgroundColor:color.fadedGreen16},answerStatusUngraded:{backgroundColor:color.fadedBlue16},buttonRow:{display:"flex"},deleteButton:{paddingInline:sizing.size_160}});const consideredButtonStyles={wrong:styles$O.answerStatusWrong,correct:styles$O.answerStatusCorrect,ungraded:styles$O.answerStatusUngraded};
1502
1504
 
1503
1505
  class FreeResponseEditor extends React.Component{render(){return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Question"}),field:jsxRuntimeExports.jsx("textarea",{value:this.props.question,onChange:e=>this.props.onChange({question:e.target.value})}),styles:{root:styles$N.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Placeholder"}),field:jsxRuntimeExports.jsx("textarea",{value:this.props.placeholder,onChange:e=>this.props.onChange({placeholder:e.target.value})}),styles:{root:styles$N.labeledInputField}}),jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Allow unlimited characters"}),field:jsxRuntimeExports.jsx(Checkbox$1,{checked:this.props.allowUnlimitedCharacters,onChange:val=>this.props.onChange({allowUnlimitedCharacters:val})}),styles:{root:styles$N.labeledInputField}}),!this.props.allowUnlimitedCharacters&&jsxRuntimeExports.jsx(LabeledField,{label:jsxRuntimeExports.jsx(HeadingSmall,{children:"Character limit"}),field:jsxRuntimeExports.jsx("input",{type:"number",min:1,value:this.props.characterLimit,onChange:this.handleUpdateCharacterLimit}),styles:{root:styles$N.labeledInputField}}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Scoring criteria"}),jsxRuntimeExports.jsx(View,{style:styles$N.criteriaList,children:this.renderCriteriaList()}),jsxRuntimeExports.jsx(View,{children:jsxRuntimeExports.jsx(Button,{onClick:this.handleAddCriterion,startIcon:plusCircle,children:"Add an item"})})]})]})}constructor(...args){super(...args),this.serialize=()=>{return {allowUnlimitedCharacters:this.props.allowUnlimitedCharacters,characterLimit:this.props.characterLimit,placeholder:this.props.placeholder,question:this.props.question,scoringCriteria:this.props.scoringCriteria}},this.getSaveWarnings=()=>{const warnings=[];if(!this.props.question){warnings.push("The question is empty");}if(this.props.question.match(Util.rWidgetRule)!=null){warnings.push("The question contains a widget");}return warnings},this.handleUpdateCharacterLimit=e=>{const val=parseInt(e.target.value);if(isNaN(val)){return}this.props.onChange({characterLimit:Math.max(1,val)});},this.handleUpdateCriterion=(index,criterion)=>{const newCriteria=this.props.scoringCriteria.map((c,i)=>{if(i===index){return criterion}return c});this.props.onChange({scoringCriteria:newCriteria});},this.handleDeleteCriterion=index=>{this.props.onChange({scoringCriteria:this.props.scoringCriteria.filter((_,i)=>i!==index)});},this.handleAddCriterion=()=>{this.props.onChange({scoringCriteria:[...this.props.scoringCriteria,{text:""}]});},this.renderCriteriaList=()=>{const isDeletable=this.props.scoringCriteria.length>1;return this.props.scoringCriteria.map((criterion,index)=>{return jsxRuntimeExports.jsx(CriterionEditor,{criterion:criterion,index:index,isDeletable:isDeletable,onChange:this.handleUpdateCriterion,onDelete:this.handleDeleteCriterion},index)})};}}FreeResponseEditor.defaultProps=freeResponseLogic.defaultWidgetOptions;FreeResponseEditor.widgetName="free-response";const CriterionEditor=function(props){return jsxRuntimeExports.jsxs(View,{style:styles$N.criterionContainer,children:[jsxRuntimeExports.jsx("textarea",{"aria-label":`Criterion ${props.index+1}`,onChange:e=>props.onChange(props.index,{text:e.target.value}),value:props.criterion.text}),props.isDeletable&&jsxRuntimeExports.jsx(View,{style:styles$N.deleteButtonContainer,children:jsxRuntimeExports.jsx(Button,{"aria-label":`Delete criterion ${props.index+1}`,actionType:"destructive",disabled:!props.isDeletable,kind:"tertiary",onClick:()=>props.onDelete(props.index),size:"small",startIcon:trashIcon$1,children:"Delete"})})]})};const styles$N=StyleSheet.create({criteriaList:{gap:spacing.small_12},criterionContainer:{paddingTop:spacing.xSmall_8,paddingBottom:spacing.xSmall_8,borderBottom:`1px solid ${semanticColor.core.border.neutral.subtle}`,":last-child":{borderBottom:"none"}},deleteButtonContainer:{display:"flex",flexDirection:"row",justifyContent:"flex-end"},labeledInputField:{paddingBottom:spacing.large_24}});
1504
1506
 
@@ -1506,15 +1508,15 @@ const{InlineIcon: InlineIcon$1,TextInput: TextInput$5}=components;class GradedGr
1506
1508
 
1507
1509
  class GradedGroupSetEditor extends React.Component{UNSAFE_componentWillMount(){this._editors=[];}render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-group-editor",children:[this.renderGroups(),jsxRuntimeExports.jsx("button",{onClick:this.addGroup,children:"Add group"})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.getSaveWarnings=()=>{return [].concat(...this._editors.map(editor=>editor?editor.getSaveWarnings():[]))},this.serialize=()=>{return {gradedGroups:this.props.gradedGroups}},this.renderGroups=()=>{if(!this.props.gradedGroups){return null}return this.props.gradedGroups.map((group,i)=>jsxRuntimeExports.jsx(GradedGroupEditor,{ref:el=>this._editors[i]=el,...group,apiOptions:this.props.apiOptions,widgetEnabled:true,immutableWidgets:false,onChange:data=>this.change("gradedGroups",setArrayItem(this.props.gradedGroups,i,{...this.props.gradedGroups[i],...data}))},i))},this.addGroup=()=>{const groups=this.props.gradedGroups||[];this.change("gradedGroups",groups.concat([GradedGroupEditor.defaultProps]));};}}GradedGroupSetEditor.propTypes={...Changeable.propTypes,apiOptions:ApiOptions.propTypes,gradedGroups:PropTypes.array,onChange:PropTypes.func.isRequired};GradedGroupSetEditor.widgetName="graded-group-set";GradedGroupSetEditor.defaultProps=gradedGroupSetLogic.defaultWidgetOptions;const setArrayItem=(list,i,value)=>[...list.slice(0,i),value,...list.slice(i+1)];
1508
1510
 
1509
- const{ButtonGroup: ButtonGroup$6,InfoTip: InfoTip$l,RangeInput: RangeInput$5}=components;const defaultBackgroundImage$1={url:null,width:0,height:0};function numSteps$1(range,step){return Math.floor((range[1]-range[0])/step)}class GraphSettings extends React.Component{getInitialState(){return this.stateFromProps(this.props)}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(this.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}stateFromProps(props){return {labelsTextbox:props.labels,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:_.clone(props.backgroundImage)}}change(...args){return Changeable.change.apply(this,args)}changeRulerLabel(e){this.change({rulerLabel:e.target.value});}changeRulerTicks(e){this.change({rulerTicks:+e.target.value});}changeBackgroundUrl(e){if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=ReactDOM.findDOMNode(this.refs["bg-url"]).value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}}renderLabelChoices(choices){return _.map(choices,function([name,value]){return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})}validRange(range){const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true}validateStepValue(settings){const{step,range,name,minTicks,maxTicks}=settings;if(!_.isFinite(step)){return name+" must be a valid number"}const nSteps=numSteps$1(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true}validSnapStep(step,range){return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})}validGridStep(step,range){return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})}validStep(step,range){return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})}validBackgroundImageSize(image){if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true}validateGraphSettings(range,step,gridStep,snapStep,image){const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true}changeLabel(i,e){const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);}changeRange(i,values){const ranges=this.state.rangeTextbox.slice();ranges[i]=values;const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scale=Util.scaleFromExtent(ranges[i],this.props.box[i]);if(this.validRange(ranges[i])===true){step[i]=Util.tickStepFromExtent(ranges[i],this.props.box[i]);gridStep[i]=Util.gridStepFromTickStep(step[i],scale);snapStep[i]=gridStep[i]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);}changeStep(step){this.setState({stepTextbox:step},this.changeGraph);}changeSnapStep(snapStep){this.setState({snapStepTextbox:snapStep},this.changeGraph);}changeGridStep(gridStep){this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);}changeGraph(){const labels=this.state.labelsTextbox;const range=_.map(this.state.rangeTextbox,function(range){return _.map(range,Number)});const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}}render(){const scale=[KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[0],this.props.box[0])),KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[1],this.props.box[1]))];const{TeX}=Dependencies.getDependencies();return jsxRuntimeExports.jsxs("div",{children:[_.contains(this.props.editableSettings,"canvas")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{htmlFor:"canvas-size",children:"Canvas size (x,y pixels)"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"canvas-size",value:this.props.box,onChange:box=>{this.change({box:box});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Scale (px per div):"," ",jsxRuntimeExports.jsx(TeX,{children:"("+scale[0]+", "+scale[1]+")"})]})]}),_.contains(this.props.editableSettings,"graph")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-x",children:"x Label"}),jsxRuntimeExports.jsx("input",{id:"labels-x",type:"text",className:"graph-settings-axis-label",ref:"labels-0",onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-y",children:"y Label"}),jsxRuntimeExports.jsx("input",{id:"labels-y",type:"text",className:"graph-settings-axis-label",ref:"labels-1",onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-x",children:"x Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-x",value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals)})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-y",children:"y Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-y",value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals)})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"tick-step",children:"Tick Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"tick-step",value:this.state.stepTextbox,onChange:this.changeStep})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"grid-step",children:"Grid Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"grid-step",value:this.state.gridStepTextbox,onChange:this.changeGridStep})]})]}),_.contains(this.props.editableSettings,"snap")&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"snap-step",children:"Snap Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"snap-step",value:this.state.snapStepTextbox,onChange:this.changeSnapStep})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Markings: "}),jsxRuntimeExports.jsx(ButtonGroup$6,{value:this.props.markings,allowEmpty:false,buttons:[{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),_.contains(this.props.editableSettings,"image")&&jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[jsxRuntimeExports.jsx("div",{children:"Background image:"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("label",{htmlFor:"bg-url",children:"Url:"}),jsxRuntimeExports.jsx("input",{id:"bg-url",type:"text",className:"graph-settings-background-url",ref:"bg-url",value:this.state.backgroundImage.url||"",onChange:e=>{const image=_.clone(this.props.backgroundImage);image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$l,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]})]}),_.contains(this.props.editableSettings,"measure")&&jsxRuntimeExports.jsxs("div",{className:"misc-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.change({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:this.changeRulerLabel,value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:this.changeRulerTicks,value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})})]})]})]})}constructor(props){super(props),this._isMounted=false;this.state=this.getInitialState();this.change=this.change.bind(this);this.changeBackgroundUrl=this.changeBackgroundUrl.bind(this);this.changeGraph=this.changeGraph.bind(this);this.changeGridStep=this.changeGridStep.bind(this);this.changeLabel=this.changeLabel.bind(this);this.changeRange=this.changeRange.bind(this);this.changeRulerLabel=this.changeRulerLabel.bind(this);this.changeRulerTicks=this.changeRulerTicks.bind(this);this.changeSnapStep=this.changeSnapStep.bind(this);this.changeStep=this.changeStep.bind(this);}}GraphSettings.defaultProps={editableSettings:["graph","snap","image","measure"],box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage$1,markings:"graph",rulerLabel:"",rulerTicks:10,showProtractor:false,showRuler:false,showTooltips:false};
1511
+ const{ButtonGroup: ButtonGroup$6,InfoTip: InfoTip$k,RangeInput: RangeInput$5}=components;const defaultBackgroundImage$1={url:null,width:0,height:0};function numSteps$1(range,step){return Math.floor((range[1]-range[0])/step)}class GraphSettings extends React.Component{getInitialState(){return this.stateFromProps(this.props)}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(this.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}stateFromProps(props){return {labelsTextbox:props.labels,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,backgroundImage:_.clone(props.backgroundImage)}}change(...args){return Changeable.change.apply(this,args)}changeRulerLabel(e){this.change({rulerLabel:e.target.value});}changeRulerTicks(e){this.change({rulerTicks:+e.target.value});}changeBackgroundUrl(e){if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image=_.clone(this.props.backgroundImage);image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=ReactDOM.findDOMNode(this.refs["bg-url"]).value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}}renderLabelChoices(choices){return _.map(choices,function([name,value]){return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})}validRange(range){const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true}validateStepValue(settings){const{step,range,name,minTicks,maxTicks}=settings;if(!_.isFinite(step)){return name+" must be a valid number"}const nSteps=numSteps$1(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true}validSnapStep(step,range){return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})}validGridStep(step,range){return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})}validStep(step,range){return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})}validBackgroundImageSize(image){if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true}validateGraphSettings(range,step,gridStep,snapStep,image){const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true}changeLabel(i,e){const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);}changeRange(i,values){const ranges=this.state.rangeTextbox.slice();ranges[i]=values;const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scale=Util.scaleFromExtent(ranges[i],this.props.box[i]);if(this.validRange(ranges[i])===true){step[i]=Util.tickStepFromExtent(ranges[i],this.props.box[i]);gridStep[i]=Util.gridStepFromTickStep(step[i],scale);snapStep[i]=gridStep[i]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);}changeStep(step){this.setState({stepTextbox:step},this.changeGraph);}changeSnapStep(snapStep){this.setState({snapStepTextbox:snapStep},this.changeGraph);}changeGridStep(gridStep){this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);}changeGraph(){const labels=this.state.labelsTextbox;const range=_.map(this.state.rangeTextbox,function(range){return _.map(range,Number)});const step=_.map(this.state.stepTextbox,Number);const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,range:range,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}}render(){const scale=[KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[0],this.props.box[0])),KhanMath.roundTo(2,Util.scaleFromExtent(this.props.range[1],this.props.box[1]))];const{TeX}=Dependencies.getDependencies();return jsxRuntimeExports.jsxs("div",{children:[_.contains(this.props.editableSettings,"canvas")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{htmlFor:"canvas-size",children:"Canvas size (x,y pixels)"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"canvas-size",value:this.props.box,onChange:box=>{this.change({box:box});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Scale (px per div):"," ",jsxRuntimeExports.jsx(TeX,{children:"("+scale[0]+", "+scale[1]+")"})]})]}),_.contains(this.props.editableSettings,"graph")&&jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-x",children:"x Label"}),jsxRuntimeExports.jsx("input",{id:"labels-x",type:"text",className:"graph-settings-axis-label",ref:"labels-0",onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"labels-y",children:"y Label"}),jsxRuntimeExports.jsx("input",{id:"labels-y",type:"text",className:"graph-settings-axis-label",ref:"labels-1",onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-x",children:"x Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-x",value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals)})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"range-y",children:"y Range"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"range-y",value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals)})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"tick-step",children:"Tick Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"tick-step",value:this.state.stepTextbox,onChange:this.changeStep})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"grid-step",children:"Grid Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"grid-step",value:this.state.gridStepTextbox,onChange:this.changeGridStep})]})]}),_.contains(this.props.editableSettings,"snap")&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:[jsxRuntimeExports.jsx("label",{htmlFor:"snap-step",children:"Snap Step"}),jsxRuntimeExports.jsx(RangeInput$5,{id:"snap-step",value:this.state.snapStepTextbox,onChange:this.changeSnapStep})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Markings: "}),jsxRuntimeExports.jsx(ButtonGroup$6,{value:this.props.markings,allowEmpty:false,buttons:[{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),_.contains(this.props.editableSettings,"image")&&jsxRuntimeExports.jsxs("div",{className:"image-settings",children:[jsxRuntimeExports.jsx("div",{children:"Background image:"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("label",{htmlFor:"bg-url",children:"Url:"}),jsxRuntimeExports.jsx("input",{id:"bg-url",type:"text",className:"graph-settings-background-url",ref:"bg-url",value:this.state.backgroundImage.url||"",onChange:e=>{const image=_.clone(this.props.backgroundImage);image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$k,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]})]}),_.contains(this.props.editableSettings,"measure")&&jsxRuntimeExports.jsxs("div",{className:"misc-settings",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.change({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:this.changeRulerLabel,value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:this.changeRulerTicks,value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})})]})]})]})}constructor(props){super(props),this._isMounted=false;this.state=this.getInitialState();this.change=this.change.bind(this);this.changeBackgroundUrl=this.changeBackgroundUrl.bind(this);this.changeGraph=this.changeGraph.bind(this);this.changeGridStep=this.changeGridStep.bind(this);this.changeLabel=this.changeLabel.bind(this);this.changeRange=this.changeRange.bind(this);this.changeRulerLabel=this.changeRulerLabel.bind(this);this.changeRulerTicks=this.changeRulerTicks.bind(this);this.changeSnapStep=this.changeSnapStep.bind(this);this.changeStep=this.changeStep.bind(this);}}GraphSettings.defaultProps={editableSettings:["graph","snap","image","measure"],box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["x","y"],range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage$1,markings:"graph",rulerLabel:"",rulerTicks:10,showProtractor:false,showRuler:false,showTooltips:false};
1510
1512
 
1511
- const{InfoTip: InfoTip$k,MultiButtonGroup}=components;const Grapher=GrapherWidget.widget;const{chooseType,defaultPlotProps,getEquationString,typeToButton}=GrapherUtil;class GrapherEditor extends React.Component{render(){const sizeClass=containerSizeClass.SMALL;let equationString;let graph;if(this.props.graph.valid===true){const graphProps={apiOptions:this.props.apiOptions,containerSizeClass:sizeClass,graph:this.props.graph,userInput:this.props.correct,correct:this.props.correct,handleUserInput:(userInput,cb)=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct},cb);},availableTypes:this.props.availableTypes,trackInteraction:function(){},static:this.props.apiOptions.editingDisabled};graph=jsxRuntimeExports.jsx(Grapher,{...graphProps});equationString=getEquationString(graphProps.userInput);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.graph.valid});}return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsx(InfoTip$k,{children:jsxRuntimeExports.jsx("p",{children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."})})," ",": ",equationString]}),jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["graph","snap","image"],box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.graph.range,labels:this.props.graph.labels,step:this.props.graph.step,gridStep:this.props.graph.gridStep,snapStep:this.props.graph.snapStep,valid:this.props.graph.valid,backgroundImage:this.props.graph.backgroundImage,markings:this.props.graph.markings,rulerLabel:this.props.graph.rulerLabel,rulerTicks:this.props.graph.rulerTicks,showTooltips:this.props.graph.showTooltips,onChange:this.change("graph")}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:_.map(GrapherUtil$1.allTypes,typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!_.contains(newAvailableTypes,this.props.correct.type)){const graph=this.props.graph;const newType=chooseType(newAvailableTypes);correct=defaultPlotProps(newType,graph);}this.props.onChange({availableTypes:newAvailableTypes,correct:correct});},this.serialize=()=>{return _.chain(this.props).pick("correct","availableTypes").extend({graph:_.omit(this.props.graph,"box")}).value()};}}GrapherEditor.propTypes={...Changeable.propTypes};GrapherEditor.widgetName="grapher";GrapherEditor.defaultProps=grapherLogic.defaultWidgetOptions;
1513
+ const{InfoTip: InfoTip$j,MultiButtonGroup}=components;const Grapher=GrapherWidget.widget;const{chooseType,defaultPlotProps,getEquationString,typeToButton}=GrapherUtil;class GrapherEditor extends React.Component{render(){const sizeClass=containerSizeClass.SMALL;let equationString;let graph;if(this.props.graph.valid===true){const graphProps={apiOptions:this.props.apiOptions,containerSizeClass:sizeClass,graph:this.props.graph,userInput:this.props.correct,correct:this.props.correct,handleUserInput:(userInput,cb)=>{let correct=this.props.correct;if(correct.type===userInput?.type){correct=_.extend({},correct,userInput);}else {correct=userInput;}this.props.onChange({correct:correct},cb);},availableTypes:this.props.availableTypes,trackInteraction:function(){},static:this.props.apiOptions.editingDisabled};graph=jsxRuntimeExports.jsx(Grapher,{...graphProps});equationString=getEquationString(graphProps.userInput);}else {graph=jsxRuntimeExports.jsx("div",{className:"perseus-error",children:this.props.graph.valid});}return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:["Correct answer"," ",jsxRuntimeExports.jsx(InfoTip$j,{children:jsxRuntimeExports.jsx("p",{children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."})})," ",": ",equationString]}),jsxRuntimeExports.jsx(GraphSettings,{editableSettings:["graph","snap","image"],box:getInteractiveBoxFromSizeClass(sizeClass),range:this.props.graph.range,labels:this.props.graph.labels,step:this.props.graph.step,gridStep:this.props.graph.gridStep,snapStep:this.props.graph.snapStep,valid:this.props.graph.valid,backgroundImage:this.props.graph.backgroundImage,markings:this.props.graph.markings,rulerLabel:this.props.graph.rulerLabel,rulerTicks:this.props.graph.rulerTicks,showTooltips:this.props.graph.showTooltips,onChange:this.change("graph")}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Available functions: "}),jsxRuntimeExports.jsx(MultiButtonGroup,{allowEmpty:false,values:this.props.availableTypes,buttons:_.map(GrapherUtil$1.allTypes,typeToButton),onChange:this.handleAvailableTypesChange})]}),graph]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleAvailableTypesChange=newAvailableTypes=>{let correct=this.props.correct;if(!_.contains(newAvailableTypes,this.props.correct.type)){const graph=this.props.graph;const newType=chooseType(newAvailableTypes);correct=defaultPlotProps(newType,graph);}this.props.onChange({availableTypes:newAvailableTypes,correct:correct});},this.serialize=()=>{return _.chain(this.props).pick("correct","availableTypes").extend({graph:_.omit(this.props.graph,"box")}).value()};}}GrapherEditor.propTypes={...Changeable.propTypes};GrapherEditor.widgetName="grapher";GrapherEditor.defaultProps=grapherLogic.defaultWidgetOptions;
1512
1514
 
1513
1515
  class GroupEditor extends React.Component{render(){return jsxRuntimeExports.jsx("div",{className:"perseus-group-editor",children:jsxRuntimeExports.jsx(Editor,{ref:this.editor,content:this.props.content,widgets:this.props.widgets,apiOptions:this.props.apiOptions,images:this.props.images,widgetEnabled:true,immutableWidgets:false,onChange:this.props.onChange})})}constructor(...args){super(...args),this.editor=React.createRef(),this.getSaveWarnings=()=>{return this.editor.current?.getSaveWarnings()},this.serialize=()=>{return _.extend({},this.editor.current?.serialize())};}}GroupEditor.propTypes={content:PropTypes.string,widgets:PropTypes.object,images:PropTypes.object,apiOptions:ApiOptions.propTypes};GroupEditor.widgetName="group";GroupEditor.defaultProps=groupLogic.defaultWidgetOptions;
1514
1516
 
1515
1517
  class PairEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("fieldset",{children:[jsxRuntimeExports.jsxs("label",{children:["Name:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.name,onChange:this.change("name")})]}),jsxRuntimeExports.jsxs("label",{children:["Value:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.value,onChange:this.change("value")})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PairEditor.propTypes={...Changeable.propTypes,name:PropTypes.string,value:PropTypes.string};PairEditor.defaultProps={name:"",value:""};class PairsEditor extends React.Component{render(){const editors=_.map(this.props.pairs,(pair,i)=>{return jsxRuntimeExports.jsx(PairEditor,{name:pair.name,value:pair.value,onChange:this.handlePairChange.bind(this,i)},i)});return jsxRuntimeExports.jsx("div",{children:editors})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handlePairChange=(pairIndex,pair)=>{const pairs=this.props.pairs.slice();pairs[pairIndex]=pair;const lastPair=pairs[pairs.length-1];if(lastPair.name&&lastPair.value){pairs.push({name:"",value:""});}this.change("pairs",pairs);},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PairsEditor.propTypes={...Changeable.propTypes,pairs:PropTypes.arrayOf(PropTypes.shape({name:PropTypes.string,value:PropTypes.string})).isRequired};class IframeEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{style:{fontWeight:"bold",textAlign:"center"},children:["This widget is deprecated! ",jsxRuntimeExports.jsx("br",{}),"Try using the Video or CS Program widgets instead."]}),jsxRuntimeExports.jsxs("label",{children:["Url or Program ID:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.url,onChange:this.change("url")})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Settings:",jsxRuntimeExports.jsx(PairsEditor,{name:"settings",pairs:this.props.settings,onChange:this.handleSettingsChange})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Width:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.width,onChange:this.change("width")})]}),jsxRuntimeExports.jsxs("label",{children:["Height:",jsxRuntimeExports.jsx(BlurInput,{value:this.props.height,onChange:this.change("height")})]}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Allow full screen",checked:this.props.allowFullScreen,onChange:value=>{this.props.onChange({allowFullScreen:value});}}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(Checkbox$1,{label:"Allow iframe content to redirect the page",checked:this.props.allowTopNavigation,onChange:value=>{this.props.onChange({allowTopNavigation:value});}})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleSettingsChange=settings=>{this.change({settings:settings.pairs});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}IframeEditor.propTypes={...Changeable.propTypes};IframeEditor.widgetName="iframe";IframeEditor.defaultProps=iframeLogic.defaultWidgetOptions;
1516
1518
 
1517
- const AutoResizingTextArea=props=>{const textAreaRef=React.useRef(null);React.useEffect(()=>{const textArea=textAreaRef.current;if(textArea){textArea.style.height="42px";textArea.style.height=`${textArea.scrollHeight}px`;}},[props.value]);return jsxRuntimeExports.jsx(TextArea,{...props,ref:textAreaRef,resizeType:"none",style:{overflow:"hidden",...props.style}})};
1519
+ const{SvgImage}=components;function ImagePreview({src,alt,width,height}){return jsxRuntimeExports.jsx("div",{className:"perseus-image-preview-container",children:jsxRuntimeExports.jsx(SvgImage,{src:src,alt:alt,width:width,height:height,allowZoom:false})})}
1518
1520
 
1519
1521
  const wbFieldStyles={root:{marginBlockEnd:sizing.size_080},label:{paddingBlockEnd:sizing.size_040}};const wbFieldStylesWithDescription={...wbFieldStyles,label:{...wbFieldStyles.label,paddingBlockEnd:0},description:{paddingBlockStart:0,paddingBlockEnd:sizing.size_040}};function getOtherSideLengthWithPreservedAspectRatio(sideLength,otherSideLength,newSideLength){if(sideLength===0){return NaN}if(newSideLength===0||otherSideLength===0){return NaN}return newSideLength*otherSideLength/sideLength}
1520
1522
 
@@ -1522,7 +1524,7 @@ const typographyMap={small:LabelSmall,medium:LabelMedium};const LabeledSwitch=pr
1522
1524
 
1523
1525
  var styles$K = {"decorativeToggleContainer":"perseus_gWNmMo2D","flexRow":"perseus_IFt-b1c6"};
1524
1526
 
1525
- const{InfoTip: InfoTip$j}=components;function DecorativeToggle({decorative,hasPopulatedFields,onChange}){function handleDecorativeToggle(newValue){if(!newValue){onChange({decorative:false});return}if(!hasPopulatedFields){onChange({decorative:true});return}const shouldReset=window.confirm("Setting this image as decorative will automatically reset all other fields (title, caption, alt text, and long description). Do you want to continue?");if(shouldReset){onChange({decorative:true,alt:"",caption:undefined,title:undefined,longDescription:undefined});}}return jsxRuntimeExports.jsx("div",{className:styles$K.decorativeToggleContainer,children:jsxRuntimeExports.jsxs("div",{className:styles$K.flexRow,children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Decorative",checked:decorative??false,onChange:handleDecorativeToggle}),jsxRuntimeExports.jsx(InfoTip$j,{children:jsxRuntimeExports.jsx("p",{children:"Mark this image as decorative and it will not have any alt text, description, title, or caption."})})]})})}
1527
+ const{InfoTip: InfoTip$i}=components;function DecorativeToggle({decorative,hasPopulatedFields,onChange}){function handleDecorativeToggle(newValue){if(!newValue){onChange({decorative:false});return}if(!hasPopulatedFields){onChange({decorative:true});return}const shouldReset=window.confirm("Setting this image as decorative will automatically reset all other fields (title, caption, alt text, and long description). Do you want to continue?");if(shouldReset){onChange({decorative:true,alt:"",caption:undefined,title:undefined,longDescription:undefined});}}return jsxRuntimeExports.jsx("div",{className:styles$K.decorativeToggleContainer,children:jsxRuntimeExports.jsxs("div",{className:styles$K.flexRow,children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Decorative",checked:decorative??false,onChange:handleDecorativeToggle}),jsxRuntimeExports.jsx(InfoTip$i,{children:jsxRuntimeExports.jsx("p",{children:"Mark this image as decorative and it will not have any alt text, description, title, or caption."})})]})})}
1526
1528
 
1527
1529
  const ScrolllessNumberTextField=props=>{const{value,onChange,...restOfProps}=props;const[focused,setFocused]=React.useState(false);const[wipValue,setWipValue]=React.useState("");const inputRef=React.useRef(null);React.useEffect(()=>{const ref=inputRef.current;const ignoreScroll=e=>{e.stopPropagation();};ref?.addEventListener("wheel",ignoreScroll);return ()=>{ref?.removeEventListener("wheel",ignoreScroll);}},[inputRef]);return jsxRuntimeExports.jsx(TextField,{...restOfProps,type:"number",value:focused?wipValue:value,onChange:newValue=>{setWipValue(newValue);onChange(newValue);},onFocus:e=>{setWipValue(value);setFocused(true);props.onFocus?.(e);},onBlur:e=>{setFocused(false);props.onBlur?.(e);},ref:inputRef})};
1528
1530
 
@@ -1530,13 +1532,13 @@ var styles$J = {"dimensionsContainer":"perseus_4qo24hC2","dimensionsFieldContain
1530
1532
 
1531
1533
  function ImageDimensionsInput({backgroundImage,onChange}){function handleWidthChange(newWidth){const newHeight=getOtherSideLengthWithPreservedAspectRatio(backgroundImage.width,backgroundImage.height,Number(newWidth));if(isNaN(newHeight)){return}onChange({backgroundImage:{...backgroundImage,width:Number(newWidth),height:newHeight}});}function handleHeightChange(newHeight){const newWidth=getOtherSideLengthWithPreservedAspectRatio(backgroundImage.height,backgroundImage.width,Number(newHeight));if(isNaN(newWidth)){return}onChange({backgroundImage:{...backgroundImage,height:Number(newHeight),width:newWidth}});}async function handleResetToOriginalSize(){const naturalSize=await Util.getImageSizeModern(backgroundImage.url);const[naturalWidth,naturalHeight]=naturalSize;if(naturalWidth===backgroundImage.width&&naturalHeight===backgroundImage.height){return}onChange({backgroundImage:{...backgroundImage,width:naturalWidth,height:naturalHeight}});}return jsxRuntimeExports.jsxs("div",{className:styles$J.dimensionsContainer,children:[jsxRuntimeExports.jsxs("div",{className:styles$J.dimensionsFieldContainer,children:[jsxRuntimeExports.jsx(LabeledField,{label:"Width",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:backgroundImage.width?.toString()??"",onChange:handleWidthChange}),styles:wbFieldStyles}),jsxRuntimeExports.jsx("span",{className:styles$J.xSpan,children:"x"}),jsxRuntimeExports.jsx(LabeledField,{label:"Height",field:jsxRuntimeExports.jsx(ScrolllessNumberTextField,{value:backgroundImage.height?.toString()??"",onChange:handleHeightChange}),styles:wbFieldStyles})]}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",size:"small",startIcon:arrowCounterClockwise,onClick:handleResetToOriginalSize,children:"Reset to original size"})]})}
1532
1534
 
1533
- const{SvgImage: SvgImage$1}=components;const MIN_ALT_TEXT_LENGTH=8;const MAX_ALT_TEXT_LENGTH=150;const altTextTooLongError="Alt text should not exceed 150 characters. Please pair your alt with a long description below if you need significantly more text to sufficiently describe the image.";const altTextTooShortError="Add more detail to describe your image. While alt text should be brief, it must also describe the image well.";function ImageSettings({alt,backgroundImage,apiOptions,caption,decorative,longDescription,title,onChange}){const imageUpgradeFF=isFeatureOn({apiOptions},"image-widget-upgrade");const[altFieldError,setAltFieldError]=React.useState(null);if(!backgroundImage.url||!backgroundImage.width||!backgroundImage.height){return null}const hasPopulatedFields=Boolean(alt||caption||title||longDescription);function handleAltFieldChange(value){if(value.length===0){setAltFieldError(null);}else if(imageUpgradeFF&&value.length>MAX_ALT_TEXT_LENGTH){setAltFieldError(altTextTooLongError);}else if(value.length>=MIN_ALT_TEXT_LENGTH){setAltFieldError(null);}onChange({alt:value});}function handleAltFieldBlur(value){if(value.length>0&&value.length<MIN_ALT_TEXT_LENGTH){setAltFieldError(altTextTooShortError);}}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Preview",field:jsxRuntimeExports.jsx(SvgImage$1,{src:backgroundImage.url,alt:`Preview: ${alt||"No alt text"}`,allowZoom:false}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(ImageDimensionsInput,{backgroundImage:backgroundImage,onChange:onChange}),imageUpgradeFF&&jsxRuntimeExports.jsx(DecorativeToggle,{decorative:decorative,hasPopulatedFields:hasPopulatedFields,onChange:onChange}),jsxRuntimeExports.jsx(LabeledField,{label:"Title",field:jsxRuntimeExports.jsx(AutoResizingTextArea,{value:title??"",onChange:value=>onChange({title:value}),disabled:decorative}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Alt text",description:"Summarize the image using up to 150 characters.",field:jsxRuntimeExports.jsx(AutoResizingTextArea,{value:alt??"",onBlur:e=>handleAltFieldBlur(e.target.value),onChange:handleAltFieldChange,disabled:decorative}),errorMessage:altFieldError,styles:wbFieldStylesWithDescription}),imageUpgradeFF&&jsxRuntimeExports.jsx(LabeledField,{label:"Long description",field:jsxRuntimeExports.jsx(AutoResizingTextArea,{value:longDescription??"",onChange:value=>onChange({longDescription:value}),disabled:decorative}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Caption",field:jsxRuntimeExports.jsx(AutoResizingTextArea,{value:caption??"",onChange:value=>onChange({caption:value}),disabled:decorative}),styles:wbFieldStyles})]})}
1535
+ const MIN_ALT_TEXT_LENGTH=8;const MAX_ALT_TEXT_LENGTH=150;const altTextTooLongError="Alt text should not exceed 150 characters. Please pair your alt with a long description below if you need significantly more text to sufficiently describe the image.";const altTextTooShortError="Add more detail to describe your image. While alt text should be brief, it must also describe the image well.";function ImageSettings({alt,backgroundImage,apiOptions,caption,decorative,longDescription,title,onChange}){const imageUpgradeFF=isFeatureOn({apiOptions},"image-widget-upgrade");const[altFieldError,setAltFieldError]=React.useState(null);if(!backgroundImage.url||!backgroundImage.width||!backgroundImage.height){return null}const hasPopulatedFields=Boolean(alt||caption||title||longDescription);function handleAltFieldChange(value){if(value.length===0){setAltFieldError(null);}else if(imageUpgradeFF&&value.length>MAX_ALT_TEXT_LENGTH){setAltFieldError(altTextTooLongError);}else if(value.length>=MIN_ALT_TEXT_LENGTH){setAltFieldError(null);}onChange({alt:value});}function handleAltFieldBlur(value){if(value.length>0&&value.length<MIN_ALT_TEXT_LENGTH){setAltFieldError(altTextTooShortError);}}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Preview",field:jsxRuntimeExports.jsx(ImagePreview,{src:backgroundImage.url,alt:`Preview: ${alt||"No alt text"}`,width:backgroundImage.width,height:backgroundImage.height}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(ImageDimensionsInput,{backgroundImage:backgroundImage,onChange:onChange}),imageUpgradeFF&&jsxRuntimeExports.jsx(DecorativeToggle,{decorative:decorative,hasPopulatedFields:hasPopulatedFields,onChange:onChange}),jsxRuntimeExports.jsx(LabeledField,{label:"Title",field:jsxRuntimeExports.jsx(TextArea,{value:title??"",onChange:value=>onChange({title:value}),disabled:decorative,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Alt text",description:"Summarize the image using up to 150 characters.",field:jsxRuntimeExports.jsx(TextArea,{value:alt??"",onBlur:e=>handleAltFieldBlur(e.target.value),onChange:handleAltFieldChange,disabled:decorative,autoResize:true}),errorMessage:altFieldError,styles:wbFieldStylesWithDescription}),imageUpgradeFF&&jsxRuntimeExports.jsx(LabeledField,{label:"Long description",field:jsxRuntimeExports.jsx(TextArea,{value:longDescription??"",onChange:value=>onChange({longDescription:value}),disabled:decorative,autoResize:true}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Caption",field:jsxRuntimeExports.jsx(TextArea,{value:caption??"",onChange:value=>onChange({caption:value}),disabled:decorative,autoResize:true}),styles:wbFieldStyles})]})}
1534
1536
 
1535
1537
  const INTERNALLY_HOSTED_DOMAINS="("+"ka-.*.s3.amazonaws.com|"+"(fastly|cdn).kastatic.org|"+"khanacademy.org|"+"kasandbox.org"+")";const INTERNALLY_HOSTED_URL_RE=new RegExp("^(https?|web\\+graphie)://[^/]*"+INTERNALLY_HOSTED_DOMAINS);function ImageUrlInput({backgroundImage,onChange}){const uniqueId=React__default.useId();const urlId=`${uniqueId}-url`;const[urlFieldValue,setUrlFieldValue]=React__default.useState(backgroundImage.url||"");const[backgroundImageError,setBackgroundImageError]=React__default.useState(null);function setUrl(url,width,height){const image={...backgroundImage};image.url=url;image.width=width;image.height=height;const box=[image.width,image.height];onChange({backgroundImage:image,box:box});}async function onUrlChange(url){if(!url){setBackgroundImageError(null);setUrl(url,0,0);return}if(url&&!INTERNALLY_HOSTED_URL_RE.test(url)){setBackgroundImageError("Images must be from sites hosted by Khan Academy. "+"Please input a Khan Academy-owned address, or use the "+"Add Image tool to rehost an existing image");return}setBackgroundImageError(null);try{const size=await Util.getImageSizeModern(url);setUrl(url,size[0],size[1]);}catch(error){setBackgroundImageError(`There was an error loading the image URL: ${JSON.stringify(error,null,2)}`);}}return jsxRuntimeExports.jsx(LabeledField,{label:"Image URL",description:"Paste an image or graphie image URL.",field:jsxRuntimeExports.jsx(TextField,{id:urlId,value:urlFieldValue,onBlur:e=>onUrlChange(e.target.value),onChange:value=>setUrlFieldValue(value)}),errorMessage:backgroundImageError,styles:wbFieldStylesWithDescription})}
1536
1538
 
1537
1539
  class ImageEditor extends React.Component{serialize(){return EditorJsonify.serialize.call(this)}render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-image-editor",children:[jsxRuntimeExports.jsx(ImageUrlInput,{...this.props}),this.props.backgroundImage.url&&jsxRuntimeExports.jsx(ImageSettings,{...this.props})]})}}ImageEditor.displayName="ImageEditor";ImageEditor.widgetName="image";ImageEditor.defaultProps=imageLogic.defaultWidgetOptions;
1538
1540
 
1539
- const{InfoTip: InfoTip$i}=components;class InputNumberEditor extends React.Component{render(){const answerTypeOptions=_.map(inputNumberAnswerTypes,function(v,k){return jsxRuntimeExports.jsx("option",{value:k,children:v.name},k)},this);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Correct answer:"," ",jsxRuntimeExports.jsx(BlurInput,{value:""+this.props.value,onChange:this.handleAnswerChange,ref:this.input})]})}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Unsimplified answers"," ",jsxRuntimeExports.jsxs("select",{value:this.props.simplify,onChange:e=>{this.props.onChange({simplify:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"required",children:"will not be graded"}),jsxRuntimeExports.jsx("option",{value:"optional",children:"will be accepted"}),jsxRuntimeExports.jsx("option",{value:"enforced",children:"will be marked wrong"})]})]}),jsxRuntimeExports.jsxs(InfoTip$i,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "will not be graded". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be marked wrong" only if we are specifically assessing the ability to simplify.'})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.inexact,onChange:e=>{this.props.onChange({inexact:e.target.checked});}})," ","Allow inexact answers"]}),jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",style:{visibility:"hidden"}}),"Max error:"," ",jsxRuntimeExports.jsx("input",{type:"text",disabled:!this.props.inexact,defaultValue:this.props.maxError,"aria-label":"Max error",onBlur:e=>{const ans=""+(Util.firstNumericalParse(e.target.value)||0);e.target.value=ans;this.props.onChange({maxError:ans});}})]})]}),jsxRuntimeExports.jsxs("div",{children:["Answer type:"," ",jsxRuntimeExports.jsx("select",{value:this.props.answerType,onChange:e=>{this.props.onChange({answerType:e.target.value});},"aria-label":"Answer type",children:answerTypeOptions}),jsxRuntimeExports.jsx(InfoTip$i,{children:jsxRuntimeExports.jsx("p",{children:'Use the default "Numbers" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions).'})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Width"," ",jsxRuntimeExports.jsxs("select",{value:this.props.size,onChange:e=>{this.props.onChange({size:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"normal",children:"Normal (80px)"}),jsxRuntimeExports.jsx("option",{value:"small",children:"Small (40px)"})]})]}),jsxRuntimeExports.jsx(InfoTip$i,{children:jsxRuntimeExports.jsx("p",{children:'Use size "Normal" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them.'})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.rightAlign,onChange:e=>{this.props.onChange({rightAlign:e.target.checked});}})," ","Right alignment"]})})]})}constructor(...args){super(...args),this.input=React.createRef(),this.handleAnswerChange=str=>{const value=Util.firstNumericalParse(str)||0;this.props.onChange({value:value});},this.focus=()=>{this.input.current?.focus();return true},this.serialize=()=>({value:this.props.value,simplify:this.props.simplify,size:this.props.size,inexact:this.props.inexact,maxError:this.props.maxError,answerType:this.props.answerType,rightAlign:this.props.rightAlign});}}InputNumberEditor.widgetName="input-number";InputNumberEditor.defaultProps=inputNumberLogic.defaultWidgetOptions;
1541
+ const{InfoTip: InfoTip$h}=components;class InputNumberEditor extends React.Component{render(){const answerTypeOptions=_.map(inputNumberAnswerTypes,function(v,k){return jsxRuntimeExports.jsx("option",{value:k,children:v.name},k)},this);return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Correct answer:"," ",jsxRuntimeExports.jsx(BlurInput,{value:""+this.props.value,onChange:this.handleAnswerChange,ref:this.input})]})}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Unsimplified answers"," ",jsxRuntimeExports.jsxs("select",{value:this.props.simplify,onChange:e=>{this.props.onChange({simplify:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"required",children:"will not be graded"}),jsxRuntimeExports.jsx("option",{value:"optional",children:"will be accepted"}),jsxRuntimeExports.jsx("option",{value:"enforced",children:"will be marked wrong"})]})]}),jsxRuntimeExports.jsxs(InfoTip$h,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "will not be graded". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and anything after)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsx("p",{children:'Select "will be marked wrong" only if we are specifically assessing the ability to simplify.'})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.inexact,onChange:e=>{this.props.onChange({inexact:e.target.checked});}})," ","Allow inexact answers"]}),jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",style:{visibility:"hidden"}}),"Max error:"," ",jsxRuntimeExports.jsx("input",{type:"text",disabled:!this.props.inexact,defaultValue:this.props.maxError,"aria-label":"Max error",onBlur:e=>{const ans=""+(Util.firstNumericalParse(e.target.value)||0);e.target.value=ans;this.props.onChange({maxError:ans});}})]})]}),jsxRuntimeExports.jsxs("div",{children:["Answer type:"," ",jsxRuntimeExports.jsx("select",{value:this.props.answerType,onChange:e=>{this.props.onChange({answerType:e.target.value});},"aria-label":"Answer type",children:answerTypeOptions}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:'Use the default "Numbers" unless the answer must be in a specific form (e.g., question is about converting decimals to fractions).'})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Width"," ",jsxRuntimeExports.jsxs("select",{value:this.props.size,onChange:e=>{this.props.onChange({size:e.target.value});},children:[jsxRuntimeExports.jsx("option",{value:"normal",children:"Normal (80px)"}),jsxRuntimeExports.jsx("option",{value:"small",children:"Small (40px)"})]})]}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:'Use size "Normal" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them.'})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"checkbox",checked:this.props.rightAlign,onChange:e=>{this.props.onChange({rightAlign:e.target.checked});}})," ","Right alignment"]})})]})}constructor(...args){super(...args),this.input=React.createRef(),this.handleAnswerChange=str=>{const value=Util.firstNumericalParse(str)||0;this.props.onChange({value:value});},this.focus=()=>{this.input.current?.focus();return true},this.serialize=()=>({value:this.props.value,simplify:this.props.simplify,size:this.props.size,inexact:this.props.inexact,maxError:this.props.maxError,answerType:this.props.answerType,rightAlign:this.props.rightAlign});}}InputNumberEditor.widgetName="input-number";InputNumberEditor.defaultProps=inputNumberLogic.defaultWidgetOptions;
1540
1542
 
1541
1543
  const{InlineIcon}=components;class ElementContainer extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-interaction-element",children:[jsxRuntimeExports.jsxs("a",{href:"#",className:"perseus-interaction-element-title "+(this.state.show?"open":"closed"),onClick:this.toggle,children:[this.state.show?jsxRuntimeExports.jsx(InlineIcon,{...iconChevronDown}):jsxRuntimeExports.jsx(InlineIcon,{...iconChevronRight}),this.props.title]}),jsxRuntimeExports.jsxs("div",{className:"perseus-interaction-element-content "+(this.state.show?"enter":"leave"),children:[this.props.children,(this.props.onUp!=null||this.props.onDown!=null||this.props.onDelete!=null)&&jsxRuntimeExports.jsxs("div",{className:"edit-controls",children:[this.props.onUp!=null&&jsxRuntimeExports.jsx("button",{onClick:this.props.onUp,children:jsxRuntimeExports.jsx(InlineIcon,{...iconCircleArrowUp})}),this.props.onDown!=null&&jsxRuntimeExports.jsx("button",{onClick:this.props.onDown,children:jsxRuntimeExports.jsx(InlineIcon,{...iconCircleArrowDown})}),this.props.onDelete!=null&&jsxRuntimeExports.jsx("button",{onClick:this.props.onDelete,children:jsxRuntimeExports.jsx(InlineIcon,{...iconTrash})})]})]})]})}constructor(props){super(props),this.toggle=e=>{e.preventDefault();this.setState({show:!this.state.show});};this.state={show:props.initiallyVisible};}}ElementContainer.defaultProps={initiallyVisible:false,title:"More"};
1542
1544
 
@@ -1572,7 +1574,7 @@ var styles$H = {"singleSelectShort":"perseus_wAZzFxEx","row":"perseus_6FquBkGo"}
1572
1574
 
1573
1575
  const LabeledRow=props=>{const{children,label,labelSide="left",style}=props;return jsxRuntimeExports.jsx("label",{className:css(styles$G.label),children:jsxRuntimeExports.jsxs(View,{style:[styles$G.row,style],children:[labelSide==="start"||jsxRuntimeExports.jsx(LabelSmall,{style:styles$G.spaceEnd,children:label}),children,labelSide==="end"&&jsxRuntimeExports.jsx(LabelSmall,{style:styles$G.spaceStart,children:label})]})})};const styles$G=StyleSheet.create({label:{width:"fit-content"},row:{flexDirection:"row",marginTop:spacing.xSmall_8,alignItems:"center",width:"fit-content"},spaceStart:{marginInlineStart:spacing.xSmall_8},spaceEnd:{marginInlineEnd:spacing.xSmall_8}});
1574
1576
 
1575
- const{InfoTip: InfoTip$h}=components;function AngleAnswerOptions({correct,graph,onChange}){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!correct?.showAngles,onChange:newValue=>{if(graph?.type==="angle"){invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);onChange({correct:{...correct,showAngles:newValue},graph:{...graph,showAngles:newValue}});}}}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Allow reflex angles"}),checked:!!correct?.allowReflexAngles,onChange:newValue=>{invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);invariant(graph?.type==="angle",`Expected graph type to be angle, but got ${graph?.type}`);const update={allowReflexAngles:newValue};onChange({correct:{...correct,...update},graph:{...graph,...update}});}}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Allow students to be able to create reflex angles."})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct.match||"exact",onChange:newValue=>{invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);onChange({correct:{...correct,match:newValue}});},placeholder:"",className:styles$H.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"})]}),jsxRuntimeExports.jsx(InfoTip$h,{children:jsxRuntimeExports.jsx("p",{children:"Congruency requires only that the angle measures are the same. An exact match implies congruency, but also requires that the angles have the same orientation and that the vertices are in the same position."})})]})]})}
1577
+ const{InfoTip: InfoTip$g}=components;function AngleAnswerOptions({correct,graph,onChange}){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!correct?.showAngles,onChange:newValue=>{if(graph?.type==="angle"){invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);onChange({correct:{...correct,showAngles:newValue},graph:{...graph,showAngles:newValue}});}}}),jsxRuntimeExports.jsx(InfoTip$g,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Allow reflex angles"}),checked:!!correct?.allowReflexAngles,onChange:newValue=>{invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);invariant(graph?.type==="angle",`Expected graph type to be angle, but got ${graph?.type}`);const update={allowReflexAngles:newValue};onChange({correct:{...correct,...update},graph:{...graph,...update}});}}),jsxRuntimeExports.jsx(InfoTip$g,{children:jsxRuntimeExports.jsx("p",{children:"Allow students to be able to create reflex angles."})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct.match||"exact",onChange:newValue=>{invariant(correct.type==="angle",`Expected graph type to be angle, but got ${correct.type}`);onChange({correct:{...correct,match:newValue}});},placeholder:"",className:styles$H.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"})]}),jsxRuntimeExports.jsx(InfoTip$g,{children:jsxRuntimeExports.jsx("p",{children:"Congruency requires only that the angle measures are the same. An exact match implies congruency, but also requires that the angles have the same orientation and that the vertices are in the same position."})})]})]})}
1576
1578
 
1577
1579
  const UNLIMITED="unlimited";const parsePointCount=points=>{const parsed=parseInt(points,10);if(isNaN(parsed)){return UNLIMITED}return parsed===0?UNLIMITED:parsed};
1578
1580
 
@@ -1584,15 +1586,15 @@ function Heading({title,isOpen,isCollapsible,onToggle}){return jsxRuntimeExports
1584
1586
 
1585
1587
  function InteractiveGraphCorrectAnswer(props){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Correct Answer",isOpen:true,isCollapsible:false}),jsxRuntimeExports.jsxs(View,{id:props.id,children:[jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabelXSmall,{style:{paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6,color:color.offBlack64},children:"Graph the correct answer in the graph below and ensure the equation or point coordinates displayed represent the correct answer."}),jsxRuntimeExports.jsx(BodyMonospace,{style:{fontSize:12,backgroundColor:"#eee",paddingInline:spacing.xxSmall_6,borderColor:"#ccc",borderStyle:"solid",borderWidth:1},children:props.equationString})]}),props.children]})]})}
1586
1588
 
1587
- function InteractiveGraphDescription(props){const{ariaLabelValue,ariaDescriptionValue,onChange}=props;const[isOpen,setIsOpen]=React.useState(true);const uniqueId=React.useId();const descriptionTextAreaId=`${uniqueId}-description-textarea`;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Description",isCollapsible:true,isOpen:isOpen,onToggle:setIsOpen}),isOpen&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabelXSmall,{style:styles$D.caption,children:"Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who may be visually impaired."}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",children:["Title",jsxRuntimeExports.jsx(TextField,{value:ariaLabelValue,onChange:newValue=>onChange({fullGraphAriaLabel:newValue||undefined}),style:styles$D.spaceAbove})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelLarge,{tag:"label",htmlFor:descriptionTextAreaId,children:"Description"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:descriptionTextAreaId,value:ariaDescriptionValue,onChange:newValue=>onChange({fullGraphAriaDescription:newValue||undefined})})]})]})}const styles$D=StyleSheet.create({caption:{color:color.offBlack64,paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},spaceAbove:{marginTop:spacing.xxxSmall_4}});
1589
+ function InteractiveGraphDescription(props){const{ariaLabelValue,ariaDescriptionValue,onChange}=props;const[isOpen,setIsOpen]=React.useState(true);const uniqueId=React.useId();const descriptionTextAreaId=`${uniqueId}-description-textarea`;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Description",isCollapsible:true,isOpen:isOpen,onToggle:setIsOpen}),isOpen&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(LabelXSmall,{style:styles$D.caption,children:"Use these fields to describe the graph as a whole. These are used by screen readers to describe content to users who may be visually impaired."}),jsxRuntimeExports.jsxs(LabelLarge,{tag:"label",children:["Title",jsxRuntimeExports.jsx(TextField,{value:ariaLabelValue,onChange:newValue=>onChange({fullGraphAriaLabel:newValue||undefined}),style:styles$D.spaceAbove})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelLarge,{tag:"label",htmlFor:descriptionTextAreaId,children:"Description"}),jsxRuntimeExports.jsx(TextArea,{id:descriptionTextAreaId,value:ariaDescriptionValue,onChange:newValue=>onChange({fullGraphAriaDescription:newValue||undefined}),autoResize:true})]})]})}const styles$D=StyleSheet.create({caption:{color:color.offBlack64,paddingTop:spacing.xxSmall_6,paddingBottom:spacing.xxSmall_6},spaceAbove:{marginTop:spacing.xxxSmall_4}});
1588
1590
 
1589
1591
  function AxisArrowSwitches(props){const{showAxisArrows,onChange,disabled}=props;return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabelSmall,{children:"Arrows"}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",style:{display:"flex",flexDirection:"row",alignItems:"center",gap:sizing.size_060},children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledSwitch,{label:"x min",labelSide:"start",size:"small",checked:showAxisArrows.xMin,disabled:disabled,onChange:()=>onChange("xMin")})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledSwitch,{label:"y min",labelSide:"start",size:"small",checked:showAxisArrows.yMin,disabled:disabled,onChange:()=>onChange("yMin")})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",style:{display:"flex",flexDirection:"row",alignItems:"center",gap:sizing.size_060},children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledSwitch,{label:"x max",labelSide:"start",size:"small",checked:showAxisArrows.xMax,disabled:disabled,onChange:()=>onChange("xMax")})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledSwitch,{label:"y max",labelSide:"start",size:"small",checked:showAxisArrows.yMax,disabled:disabled,onChange:()=>onChange("yMax")})})]})]})}
1590
1592
 
1591
- const{ButtonGroup: ButtonGroup$1,InfoTip: InfoTip$g,RangeInput: RangeInput$4}=components;const defaultBackgroundImage={url:null,width:0,height:0};function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}class InteractiveGraphSettings extends React.Component{static stateFromProps(props){return {labelsTextbox:props.labels,labelLocation:props.labelLocation,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,showAxisArrowsSwitches:props.showAxisArrows,backgroundImage:{...props.backgroundImage}}}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.labelLocation,nextProps.labelLocation)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(InteractiveGraphSettings.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}render(){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Common Graph Settings",isOpen:this.state.isExpanded,isCollapsible:true,onToggle:()=>this.setState({isExpanded:!this.state.isExpanded})}),this.state.isExpanded&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Label Location",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.labelLocation,allowEmpty:false,buttons:[{value:"onAxis",content:"On Axis"},{value:"alongEdge",content:"Along Graph Edge"}],onChange:this.change("labelLocation")})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelXRef,onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelYRef,onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals),allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals),allowPiTruncation:true})})})]}),jsxRuntimeExports.jsx(AxisArrowSwitches,{showAxisArrows:this.state.showAxisArrowsSwitches,onChange:this.changeShowAxisArrows,disabled:this.props.apiOptions?.editingDisabled??false}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Tick Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.stepTextbox,onChange:this.changeStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Grid Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.gridStepTextbox,onChange:this.changeGridStep,allowPiTruncation:true})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Snap Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.snapStepTextbox,onChange:this.changeSnapStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",onClick:()=>{this.changeStepsBasedOnRange();},children:"Auto-adjust steps"}),jsxRuntimeExports.jsxs(InfoTip$g,{children:[jsxRuntimeExports.jsx("p",{children:'Use the "Auto-adjust" steps button to update the tick step, grid step, and snap step to values that are valid for the current range.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("p",{children:"This is useful when the range is changed, and the graph errors due to the step sizes being too large or too small."})]})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Markings:",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.markings,allowEmpty:false,buttons:[{value:"axes",content:"Axes"},{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Background image URL:",style:styles$C.resetSpaceTop,children:[jsxRuntimeExports.jsx("input",{type:"text",className:css(styles$C.backgroundUrlInput),ref:this.bgUrlRef,value:this.state.backgroundImage.url||"",onChange:e=>{const image={...this.props.backgroundImage};image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$g,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),jsxRuntimeExports.jsxs(View,{style:styles$C.protractorSection,children:[jsxRuntimeExports.jsx(View,{style:styles$C.checkboxRow,children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});},style:styles$C.resetSpaceTop})}),this.props.showProtractor&&jsxRuntimeExports.jsx(Banner,{text:"The protractor is not accessible. Please consider an alternate approach.",kind:"warning"})]})]})]})}constructor(props){super(props),this._isMounted=false,this.bgUrlRef=React.createRef(),this.labelXRef=React.createRef(),this.labelYRef=React.createRef(),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.changeBackgroundUrl=e=>{if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image={...this.props.backgroundImage};image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=this.bgUrlRef.current?.value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}},this.renderLabelChoices=choices=>{return choices.map(nameAndValue=>jsxRuntimeExports.jsx("option",{value:nameAndValue[1],children:nameAndValue[0]},nameAndValue[1]))},this.validRange=range=>{const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true},this.validateStepValue=settings=>{const{step,range,name,minTicks,maxTicks}=settings;const nSteps=numSteps(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true},this.validSnapStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})},this.validGridStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})},this.validStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})},this.validBackgroundImageSize=image=>{if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true},this.validateGraphSettings=(range,step,gridStep,snapStep,image)=>{const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true},this.changeLabel=(i,e)=>{const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);},this.changeRange=(i,values)=>{const ranges=this.state.rangeTextbox.slice();ranges[i]=values;this.setState({rangeTextbox:ranges},this.changeGraph);},this.changeShowAxisArrows=axis=>{const newShowAxisArrows={...this.state.showAxisArrowsSwitches};newShowAxisArrows[axis]=!newShowAxisArrows[axis];this.setState({showAxisArrowsSwitches:newShowAxisArrows},this.changeGraph);},this.changeStepsBasedOnRange=()=>{const ranges=this.state.rangeTextbox.slice();const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scaleX=Util.scaleFromExtent(ranges[0],this.props.box[0]);if(this.validRange(ranges[0])===true){step[0]=Util.tickStepFromExtent(ranges[0],this.props.box[0]);const gridStepValue=Util.gridStepFromTickStep(step[0],scaleX);if(gridStepValue){gridStep[0]=gridStepValue;}snapStep[0]=gridStep[0]/2;}const scaleY=Util.scaleFromExtent(ranges[1],this.props.box[1]);if(this.validRange(ranges[1])===true){step[1]=Util.tickStepFromExtent(ranges[1],this.props.box[1]);const gridStepValue=Util.gridStepFromTickStep(step[1],scaleY);if(gridStepValue){gridStep[1]=gridStepValue;}snapStep[1]=gridStep[1]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);},this.changeStep=step=>{this.setState({stepTextbox:step},this.changeGraph);},this.changeSnapStep=snapStep=>{this.setState({snapStepTextbox:snapStep},this.changeGraph);},this.changeGridStep=gridStep=>{this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);},this.changeGraph=()=>{const labels=this.state.labelsTextbox;const labelLocation=this.state.labelLocation;const range=this.state.rangeTextbox.map(range=>range.map(value=>Number(value)));const showAxisArrows=this.state.showAxisArrowsSwitches;const step=this.state.stepTextbox.map(value=>Number(value));const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,labelLocation:labelLocation,range:range,showAxisArrows:showAxisArrows,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}};this.state={isExpanded:true,...InteractiveGraphSettings.stateFromProps(props)};}}InteractiveGraphSettings.defaultProps={box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage,markings:"graph",showProtractor:false,showTooltips:false,showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true}};const styles$C=StyleSheet.create({resetSpaceTop:{marginTop:0},backgroundUrlInput:{border:`1px solid ${color.offBlack32}`,borderRadius:spacing.xxxSmall_4,padding:spacing.xxxSmall_4},checkboxRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:spacing.xSmall_8},protractorSection:{marginTop:spacing.xSmall_8,borderTop:`1px solid ${color.offBlack16}`,paddingTop:spacing.xSmall_8,paddingBottom:spacing.xSmall_8,borderBottom:`1px solid ${color.offBlack16}`}});
1593
+ const{ButtonGroup: ButtonGroup$1,InfoTip: InfoTip$f,RangeInput: RangeInput$4}=components;const defaultBackgroundImage={url:null,width:0,height:0};function numSteps(range,step){return Math.floor((range[1]-range[0])/step)}class InteractiveGraphSettings extends React.Component{static stateFromProps(props){return {labelsTextbox:props.labels,labelLocation:props.labelLocation,gridStepTextbox:props.gridStep,snapStepTextbox:props.snapStep,stepTextbox:props.step,rangeTextbox:props.range,showAxisArrowsSwitches:props.showAxisArrows,backgroundImage:{...props.backgroundImage}}}componentDidMount(){this._isMounted=true;this.changeGraph=_.debounce(this.changeGraph,300);}UNSAFE_componentWillReceiveProps(nextProps){if(!_.isEqual(this.props.labels,nextProps.labels)||!_.isEqual(this.props.labelLocation,nextProps.labelLocation)||!_.isEqual(this.props.gridStep,nextProps.gridStep)||!_.isEqual(this.props.snapStep,nextProps.snapStep)||!_.isEqual(this.props.step,nextProps.step)||!_.isEqual(this.props.range,nextProps.range)||!_.isEqual(this.props.backgroundImage,nextProps.backgroundImage)){this.setState(InteractiveGraphSettings.stateFromProps(nextProps));}}componentWillUnmount(){this._isMounted=false;}render(){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Common Graph Settings",isOpen:this.state.isExpanded,isCollapsible:true,onToggle:()=>this.setState({isExpanded:!this.state.isExpanded})}),this.state.isExpanded&&jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsxs("div",{className:"graph-settings",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Label Location",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.labelLocation,allowEmpty:false,buttons:[{value:"onAxis",content:"On Axis"},{value:"alongEdge",content:"Along Graph Edge"}],onChange:this.change("labelLocation")})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelXRef,onChange:e=>this.changeLabel(0,e),value:this.state.labelsTextbox[0]||""})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Label",children:jsxRuntimeExports.jsx("input",{type:"text",className:"graph-settings-axis-label",ref:this.labelYRef,onChange:e=>this.changeLabel(1,e),value:this.state.labelsTextbox[1]||""})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"x Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[0],onChange:vals=>this.changeRange(0,vals),allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"y Range",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.rangeTextbox[1],onChange:vals=>this.changeRange(1,vals),allowPiTruncation:true})})})]}),jsxRuntimeExports.jsx(AxisArrowSwitches,{showAxisArrows:this.state.showAxisArrowsSwitches,onChange:this.changeShowAxisArrows,disabled:this.props.apiOptions?.editingDisabled??false}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Tick Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.stepTextbox,onChange:this.changeStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Grid Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.gridStepTextbox,onChange:this.changeGridStep,allowPiTruncation:true})})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Snap Step",children:jsxRuntimeExports.jsx(RangeInput$4,{value:this.state.snapStepTextbox,onChange:this.changeSnapStep,allowPiTruncation:true})})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-right-col",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",onClick:()=>{this.changeStepsBasedOnRange();},children:"Auto-adjust steps"}),jsxRuntimeExports.jsxs(InfoTip$f,{children:[jsxRuntimeExports.jsx("p",{children:'Use the "Auto-adjust" steps button to update the tick step, grid step, and snap step to values that are valid for the current range.'}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("p",{children:"This is useful when the range is changed, and the graph errors due to the step sizes being too large or too small."})]})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(LabeledRow,{label:"Markings:",children:jsxRuntimeExports.jsx(ButtonGroup$1,{value:this.props.markings,allowEmpty:false,buttons:[{value:"axes",content:"Axes"},{value:"graph",content:"Graph"},{value:"grid",content:"Grid"},{value:"none",content:"None"}],onChange:this.change("markings")})})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.change({showTooltips:value});}})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Background image URL:",style:styles$C.resetSpaceTop,children:[jsxRuntimeExports.jsx("input",{type:"text",className:css(styles$C.backgroundUrlInput),ref:this.bgUrlRef,value:this.state.backgroundImage.url||"",onChange:e=>{const image={...this.props.backgroundImage};image.url=e.target.value;this.setState({backgroundImage:image});},onKeyPress:this.changeBackgroundUrl,onBlur:this.changeBackgroundUrl}),jsxRuntimeExports.jsx(InfoTip$f,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),jsxRuntimeExports.jsxs(View,{style:styles$C.protractorSection,children:[jsxRuntimeExports.jsx(View,{style:styles$C.checkboxRow,children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.change({showProtractor:value});},style:styles$C.resetSpaceTop})}),this.props.showProtractor&&jsxRuntimeExports.jsx(Banner,{text:"The protractor is not accessible. Please consider an alternate approach.",kind:"warning"})]})]})]})}constructor(props){super(props),this._isMounted=false,this.bgUrlRef=React.createRef(),this.labelXRef=React.createRef(),this.labelYRef=React.createRef(),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.changeBackgroundUrl=e=>{if(e.type==="keypress"&&e.key!=="Enter"){return}const setUrl=(url,width,height)=>{const image={...this.props.backgroundImage};image.url=url;image.width=width;image.height=height;this.setState({backgroundImage:image},this.changeGraph);};const url=this.bgUrlRef.current?.value;if(url){Util.getImageSize(url,(width,height)=>{if(this._isMounted){setUrl(url,width,height);}});}else {setUrl(null,0,0);}},this.renderLabelChoices=choices=>{return choices.map(nameAndValue=>jsxRuntimeExports.jsx("option",{value:nameAndValue[1],children:nameAndValue[0]},nameAndValue[1]))},this.validRange=range=>{const numbers=_.every(range,function(num){return _.isFinite(num)});if(!numbers){return "Range must be a valid number"}if(range[0]>=range[1]){return "Range must have a higher number on the right"}return true},this.validateStepValue=settings=>{const{step,range,name,minTicks,maxTicks}=settings;const nSteps=numSteps(range,step);if(nSteps<minTicks){return name+" is too large, there must be at least "+minTicks+" ticks."}if(nSteps>maxTicks){return name+" is too small, there can be at most "+maxTicks+" ticks."}return true},this.validSnapStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Snap step",minTicks:5,maxTicks:60})},this.validGridStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Grid step",minTicks:3,maxTicks:60})},this.validStep=(step,range)=>{return this.validateStepValue({step:step,range:range,name:"Step",minTicks:3,maxTicks:20})},this.validBackgroundImageSize=image=>{if(!image.url){return true}const validSize=image.width<=450&&image.height<=450;if(!validSize){return "Image must be smaller than 450px x 450px."}return true},this.validateGraphSettings=(range,step,gridStep,snapStep,image)=>{const self=this;let msg;const goodRange=_.every(range,function(range){msg=self.validRange(range);return msg===true});if(!goodRange){return msg}const goodStep=_.every(step,function(step,i){msg=self.validStep(step,range[i]);return msg===true});if(!goodStep){return msg}const goodGridStep=_.every(gridStep,function(gridStep,i){msg=self.validGridStep(gridStep,range[i]);return msg===true});if(!goodGridStep){return msg}const goodSnapStep=_.every(snapStep,function(snapStep,i){msg=self.validSnapStep(snapStep,range[i]);return msg===true});if(!goodSnapStep){return msg}const goodImageSize=this.validBackgroundImageSize(image);if(goodImageSize!==true){msg=goodImageSize;return msg}return true},this.changeLabel=(i,e)=>{const val=e.target.value;const labels=this.state.labelsTextbox.slice();labels[i]=val;this.setState({labelsTextbox:labels},this.changeGraph);},this.changeRange=(i,values)=>{const ranges=this.state.rangeTextbox.slice();ranges[i]=values;this.setState({rangeTextbox:ranges},this.changeGraph);},this.changeShowAxisArrows=axis=>{const newShowAxisArrows={...this.state.showAxisArrowsSwitches};newShowAxisArrows[axis]=!newShowAxisArrows[axis];this.setState({showAxisArrowsSwitches:newShowAxisArrows},this.changeGraph);},this.changeStepsBasedOnRange=()=>{const ranges=this.state.rangeTextbox.slice();const step=this.state.stepTextbox.slice();const gridStep=this.state.gridStepTextbox.slice();const snapStep=this.state.snapStepTextbox.slice();const scaleX=Util.scaleFromExtent(ranges[0],this.props.box[0]);if(this.validRange(ranges[0])===true){step[0]=Util.tickStepFromExtent(ranges[0],this.props.box[0]);const gridStepValue=Util.gridStepFromTickStep(step[0],scaleX);if(gridStepValue){gridStep[0]=gridStepValue;}snapStep[0]=gridStep[0]/2;}const scaleY=Util.scaleFromExtent(ranges[1],this.props.box[1]);if(this.validRange(ranges[1])===true){step[1]=Util.tickStepFromExtent(ranges[1],this.props.box[1]);const gridStepValue=Util.gridStepFromTickStep(step[1],scaleY);if(gridStepValue){gridStep[1]=gridStepValue;}snapStep[1]=gridStep[1]/2;}this.setState({stepTextbox:step,gridStepTextbox:gridStep,snapStepTextbox:snapStep,rangeTextbox:ranges},this.changeGraph);},this.changeStep=step=>{this.setState({stepTextbox:step},this.changeGraph);},this.changeSnapStep=snapStep=>{this.setState({snapStepTextbox:snapStep},this.changeGraph);},this.changeGridStep=gridStep=>{this.setState({gridStepTextbox:gridStep,snapStepTextbox:_.map(gridStep,function(step){return step/2})},this.changeGraph);},this.changeGraph=()=>{const labels=this.state.labelsTextbox;const labelLocation=this.state.labelLocation;const range=this.state.rangeTextbox.map(range=>range.map(value=>Number(value)));const showAxisArrows=this.state.showAxisArrowsSwitches;const step=this.state.stepTextbox.map(value=>Number(value));const gridStep=this.state.gridStepTextbox;const snapStep=this.state.snapStepTextbox;const image=this.state.backgroundImage;const validationResult=this.validateGraphSettings(range,step,gridStep,snapStep,image);if(validationResult===true){this.change({valid:true,labels:labels,labelLocation:labelLocation,range:range,showAxisArrows:showAxisArrows,step:step,gridStep:gridStep,snapStep:snapStep,backgroundImage:image});}else {this.change({valid:validationResult});}};this.state={isExpanded:true,...InteractiveGraphSettings.stateFromProps(props)};}}InteractiveGraphSettings.defaultProps={box:[interactiveSizes.defaultBoxSizeSmall,interactiveSizes.defaultBoxSizeSmall],labels:["$x$","$y$"],labelLocation:"onAxis",range:[[-10,10],[-10,10]],step:[1,1],gridStep:[1,1],snapStep:[1,1],valid:true,backgroundImage:defaultBackgroundImage,markings:"graph",showProtractor:false,showTooltips:false,showAxisArrows:{xMin:true,xMax:true,yMin:true,yMax:true}};const styles$C=StyleSheet.create({resetSpaceTop:{marginTop:0},backgroundUrlInput:{border:`1px solid ${color.offBlack32}`,borderRadius:spacing.xxxSmall_4,padding:spacing.xxxSmall_4},checkboxRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",marginBottom:spacing.xSmall_8},protractorSection:{marginTop:spacing.xSmall_8,borderTop:`1px solid ${color.offBlack16}`,paddingTop:spacing.xSmall_8,paddingBottom:spacing.xSmall_8,borderBottom:`1px solid ${color.offBlack16}`}});
1592
1594
 
1593
- const{InfoTip: InfoTip$f}=components;const StyledUl=addStyle("ul");function getAccessibilityAttributes(graphId){const elementArias=[];const container=document.getElementById(graphId);if(!container){return elementArias}container.querySelectorAll("*").forEach(element=>{const elementAttributes=[];const ariaLabel=element.getAttribute("aria-label");const ariaDescribedby=element.getAttribute("aria-describedby");if(ariaLabel){elementAttributes.unshift({name:"label",value:ariaLabel});}if(ariaDescribedby){const descriptions=ariaDescribedby.split(/ +/);for(const description of descriptions){const descriptionString=document.getElementById(description)?.textContent;if(descriptionString){elementAttributes.push({name:"description",value:descriptionString});}}}if(elementAttributes.length>0){elementArias.push({roleOrTag:element.getAttribute("role")||element.tagName.toLowerCase(),className:element.classList[element.classList.length-1]||"",attributes:elementAttributes});}});return elementArias}function SRTree(props){const{elementArias,showTags}=props;return jsxRuntimeExports.jsx("ol",{style:{listStyle:"revert",marginLeft:8},children:elementArias.map((aria,index)=>jsxRuntimeExports.jsxs("li",{children:[showTags&&jsxRuntimeExports.jsx(Pill,{size:"small",kind:"success",style:styles$B.smallSpaceRight,children:aria.roleOrTag}),aria.className,jsxRuntimeExports.jsx(StyledUl,{style:styles$B.indentListLeft,children:aria.attributes.map((value,index)=>jsxRuntimeExports.jsxs("li",{children:[jsxRuntimeExports.jsx(Pill,{size:"small",kind:value.name==="label"?"info":"neutral",style:styles$B.smallSpaceRight,children:value.name}),value.value]},index))})]},index))})}function InteractiveGraphSRTree({graphId,correct,fullGraphAriaLabel,fullGraphAriaDescription,lockedFigures}){const[isExpanded,setIsExpanded]=React.useState(true);const[showTags,setShowTags]=React.useState(false);const[elementArias,setElementArias]=React.useState([]);const switchId=React.useId();React.useEffect(()=>{setElementArias(getAccessibilityAttributes(graphId));},[correct,fullGraphAriaLabel,fullGraphAriaDescription,graphId,lockedFigures]);return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Screen reader tree",isOpen:isExpanded,onToggle:setIsExpanded,isCollapsible:true}),isExpanded&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:[styles$B.row,styles$B.tagSwitch],children:[jsxRuntimeExports.jsx(Switch,{id:switchId,checked:showTags,onChange:setShowTags}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LabelSmall,{tag:"label",htmlFor:switchId,children:"Show HTML roles/tags"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(InfoTip$f,{children:'This screen reader tree shows the ARIA labels and descriptions for elements within the "correct answer" Interactive Graph widget displayed above.'})]}),jsxRuntimeExports.jsx(SRTree,{elementArias:elementArias,showTags:showTags})]})]})}const styles$B=StyleSheet.create({smallSpaceRight:{marginRight:spacing.xxSmall_6},indentListLeft:{listStyle:"revert",marginLeft:spacing.small_12},tagSwitch:{marginTop:spacing.xSmall_8,marginBottom:spacing.xSmall_8},row:{flexDirection:"row",alignItems:"center"}});
1595
+ const{InfoTip: InfoTip$e}=components;const StyledUl=addStyle("ul");function getAccessibilityAttributes(graphId){const elementArias=[];const container=document.getElementById(graphId);if(!container){return elementArias}container.querySelectorAll("*").forEach(element=>{const elementAttributes=[];const ariaLabel=element.getAttribute("aria-label");const ariaDescribedby=element.getAttribute("aria-describedby");if(ariaLabel){elementAttributes.unshift({name:"label",value:ariaLabel});}if(ariaDescribedby){const descriptions=ariaDescribedby.split(/ +/);for(const description of descriptions){const descriptionString=document.getElementById(description)?.textContent;if(descriptionString){elementAttributes.push({name:"description",value:descriptionString});}}}if(elementAttributes.length>0){elementArias.push({roleOrTag:element.getAttribute("role")||element.tagName.toLowerCase(),className:element.classList[element.classList.length-1]||"",attributes:elementAttributes});}});return elementArias}function SRTree(props){const{elementArias,showTags}=props;return jsxRuntimeExports.jsx("ol",{style:{listStyle:"revert",marginLeft:8},children:elementArias.map((aria,index)=>jsxRuntimeExports.jsxs("li",{children:[showTags&&jsxRuntimeExports.jsx(Pill,{size:"small",kind:"success",style:styles$B.smallSpaceRight,children:aria.roleOrTag}),aria.className,jsxRuntimeExports.jsx(StyledUl,{style:styles$B.indentListLeft,children:aria.attributes.map((value,index)=>jsxRuntimeExports.jsxs("li",{children:[jsxRuntimeExports.jsx(Pill,{size:"small",kind:value.name==="label"?"info":"neutral",style:styles$B.smallSpaceRight,children:value.name}),value.value]},index))})]},index))})}function InteractiveGraphSRTree({graphId,correct,fullGraphAriaLabel,fullGraphAriaDescription,lockedFigures}){const[isExpanded,setIsExpanded]=React.useState(true);const[showTags,setShowTags]=React.useState(false);const[elementArias,setElementArias]=React.useState([]);const switchId=React.useId();React.useEffect(()=>{setElementArias(getAccessibilityAttributes(graphId));},[correct,fullGraphAriaLabel,fullGraphAriaDescription,graphId,lockedFigures]);return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Heading,{title:"Screen reader tree",isOpen:isExpanded,onToggle:setIsExpanded,isCollapsible:true}),isExpanded&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs(View,{style:[styles$B.row,styles$B.tagSwitch],children:[jsxRuntimeExports.jsx(Switch,{id:switchId,checked:showTags,onChange:setShowTags}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(LabelSmall,{tag:"label",htmlFor:switchId,children:"Show HTML roles/tags"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(InfoTip$e,{children:'This screen reader tree shows the ARIA labels and descriptions for elements within the "correct answer" Interactive Graph widget displayed above.'})]}),jsxRuntimeExports.jsx(SRTree,{elementArias:elementArias,showTags:showTags})]})]})}const styles$B=StyleSheet.create({smallSpaceRight:{marginRight:spacing.xxSmall_6},indentListLeft:{listStyle:"revert",marginLeft:spacing.small_12},tagSwitch:{marginTop:spacing.xSmall_8,marginBottom:spacing.xSmall_8},row:{flexDirection:"row",alignItems:"center"}});
1594
1596
 
1595
- const{InfoTip: InfoTip$e}=components;const POLYGON_SIDES=_.map(_.range(3,13),function(value){return jsxRuntimeExports.jsx(OptionItem,{value:`${value}`,label:`${value} sides`},`polygon-sides-${value}`)});function PolygonAnswerOptions({correct,graph,onChange}){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Number of sides:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:correct?.numSides?`${correct.numSides}`:"3",placeholder:"",onChange:newValue=>{invariant(graph?.type==="polygon");const updates={numSides:parsePointCount(newValue),coords:undefined,startCoords:undefined,snapTo:"grid"};onChange({correct:{...correct,...updates},graph:{...graph,...updates}});},className:styles$H.singleSelectShort,children:[...POLYGON_SIDES,jsxRuntimeExports.jsx(OptionItem,{value:"unlimited",label:"unlimited sides"},"unlimited")]},"polygon-select")}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Snap to:",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct?.snapTo||"grid",placeholder:"",onChange:newValue=>{invariant(correct.type==="polygon",`Expected correct answer type to be polygon, but got ${correct.type}`);invariant(graph?.type==="polygon",`Expected graph type to be polygon, but got ${graph?.type}`);const updates={snapTo:newValue,coords:null};onChange({correct:{...correct,...updates},graph:{...graph,...updates}});},className:styles$H.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"grid",label:"grid"}),correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"angles",label:"interior angles"}),correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"sides",label:"side measures"})]}),jsxRuntimeExports.jsxs(InfoTip$e,{children:[jsxRuntimeExports.jsx("p",{children:"These options affect the movement of the vertex points. The grid option will guide the points to the nearest half step along the grid."}),jsxRuntimeExports.jsx("p",{children:"The interior angle and side measure options guide the points to the nearest whole angle or side measure respectively."})]})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!correct?.showAngles,onChange:()=>{if(graph?.type==="polygon"){invariant(correct.type==="polygon",`Expected graph type to be polygon, but got ${correct.type}`);onChange({correct:{...correct,showAngles:!correct.showAngles},graph:{...graph,showAngles:!graph.showAngles}});}}}),jsxRuntimeExports.jsx(InfoTip$e,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show side measures"}),checked:!!correct?.showSides,onChange:()=>{if(graph?.type==="polygon"&&correct.type==="polygon"){onChange({correct:{...correct,showSides:!correct.showSides},graph:{...graph,showSides:!graph.showSides}});}}}),jsxRuntimeExports.jsx(InfoTip$e,{children:jsxRuntimeExports.jsx("p",{children:"Displays the side lengths."})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct.match||"exact",onChange:newValue=>{invariant(correct.type==="polygon",`Expected graph type to be polygon, but got ${correct.type}`);const updatedCorrect={...correct,match:newValue};onChange({correct:updatedCorrect});},placeholder:"",className:styles$H.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"approx",label:"be approximately congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"similar",label:"be similar"})]}),jsxRuntimeExports.jsx(InfoTip$e,{children:jsxRuntimeExports.jsxs("ul",{children:[jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Match Exactly:"})," Match exactly in size, orientation, and location on the grid even if it is not shown in the background."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Congruent:"})," Be congruent in size and shape, but can be located anywhere on the grid."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Approximately Congruent:"})," Be exactly similar, and congruent in size and shape to within 0.1 units, but can be located anywhere on the grid."," ",jsxRuntimeExports.jsx("em",{children:"Use this with snapping to angle measure."})]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Similar:"})," Be similar with matching interior angles, and side measures that are matching or a multiple of the correct side measures. The figure can be located anywhere on the grid."]})})]})})]})]})}
1597
+ const{InfoTip: InfoTip$d}=components;const POLYGON_SIDES=_.map(_.range(3,13),function(value){return jsxRuntimeExports.jsx(OptionItem,{value:`${value}`,label:`${value} sides`},`polygon-sides-${value}`)});function PolygonAnswerOptions({correct,graph,onChange}){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledRow,{label:"Number of sides:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:correct?.numSides?`${correct.numSides}`:"3",placeholder:"",onChange:newValue=>{invariant(graph?.type==="polygon");const updates={numSides:parsePointCount(newValue),coords:undefined,startCoords:undefined,snapTo:"grid"};onChange({correct:{...correct,...updates},graph:{...graph,...updates}});},className:styles$H.singleSelectShort,children:[...POLYGON_SIDES,jsxRuntimeExports.jsx(OptionItem,{value:"unlimited",label:"unlimited sides"},"unlimited")]},"polygon-select")}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Snap to:",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct?.snapTo||"grid",placeholder:"",onChange:newValue=>{invariant(correct.type==="polygon",`Expected correct answer type to be polygon, but got ${correct.type}`);invariant(graph?.type==="polygon",`Expected graph type to be polygon, but got ${graph?.type}`);const updates={snapTo:newValue,coords:null};onChange({correct:{...correct,...updates},graph:{...graph,...updates}});},className:styles$H.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"grid",label:"grid"}),correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"angles",label:"interior angles"}),correct?.numSides!=="unlimited"&&jsxRuntimeExports.jsx(OptionItem,{value:"sides",label:"side measures"})]}),jsxRuntimeExports.jsxs(InfoTip$d,{children:[jsxRuntimeExports.jsx("p",{children:"These options affect the movement of the vertex points. The grid option will guide the points to the nearest half step along the grid."}),jsxRuntimeExports.jsx("p",{children:"The interior angle and side measure options guide the points to the nearest whole angle or side measure respectively."})]})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show angle measures"}),checked:!!correct?.showAngles,onChange:()=>{if(graph?.type==="polygon"){invariant(correct.type==="polygon",`Expected graph type to be polygon, but got ${correct.type}`);onChange({correct:{...correct,showAngles:!correct.showAngles},graph:{...graph,showAngles:!graph.showAngles}});}}}),jsxRuntimeExports.jsx(InfoTip$d,{children:jsxRuntimeExports.jsx("p",{children:"Displays the interior angle measures."})})]}),jsxRuntimeExports.jsxs(View,{className:styles$H.row,children:[jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsx(LabelSmall,{children:"Show side measures"}),checked:!!correct?.showSides,onChange:()=>{if(graph?.type==="polygon"&&correct.type==="polygon"){onChange({correct:{...correct,showSides:!correct.showSides},graph:{...graph,showSides:!graph.showSides}});}}}),jsxRuntimeExports.jsx(InfoTip$d,{children:jsxRuntimeExports.jsx("p",{children:"Displays the side lengths."})})]}),jsxRuntimeExports.jsxs(LabeledRow,{label:"Student answer must",children:[jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:correct.match||"exact",onChange:newValue=>{invariant(correct.type==="polygon",`Expected graph type to be polygon, but got ${correct.type}`);const updatedCorrect={...correct,match:newValue};onChange({correct:updatedCorrect});},placeholder:"",className:styles$H.singleSelectShort,children:[jsxRuntimeExports.jsx(OptionItem,{value:"exact",label:"match exactly"}),jsxRuntimeExports.jsx(OptionItem,{value:"congruent",label:"be congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"approx",label:"be approximately congruent"}),jsxRuntimeExports.jsx(OptionItem,{value:"similar",label:"be similar"})]}),jsxRuntimeExports.jsx(InfoTip$d,{children:jsxRuntimeExports.jsxs("ul",{children:[jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Match Exactly:"})," Match exactly in size, orientation, and location on the grid even if it is not shown in the background."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Congruent:"})," Be congruent in size and shape, but can be located anywhere on the grid."]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Approximately Congruent:"})," Be exactly similar, and congruent in size and shape to within 0.1 units, but can be located anywhere on the grid."," ",jsxRuntimeExports.jsx("em",{children:"Use this with snapping to angle measure."})]})}),jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("p",{children:[jsxRuntimeExports.jsx("b",{children:"Be Similar:"})," Be similar with matching interior angles, and side measures that are matching or a multiple of the correct side measures. The figure can be located anywhere on the grid."]})})]})})]})]})}
1596
1598
 
1597
1599
  const SegmentCountSelector=({correct,graph,onChange})=>jsxRuntimeExports.jsx(LabeledRow,{label:"Number of segments:",children:jsxRuntimeExports.jsx(SingleSelect,{selectedValue:`${correct.numSegments??1}`,placeholder:"",onChange:newValue=>{const sides=+newValue;onChange({correct:{type:"segment",numSegments:sides,coords:null},graph:{type:"segment",numSegments:sides}});},className:styles$H.singleSelectShort,children:_.range(1,7).map(n=>jsxRuntimeExports.jsx(OptionItem,{value:`${n}`,label:`${n} segment${n>1?"s":""}`},n))},"segment-select")});
1598
1600
 
@@ -1612,15 +1614,15 @@ const LineStrokeSelect=props=>{const{selectedValue,containerStyle,onChange}=prop
1612
1614
 
1613
1615
  const LineWeightSelect=props=>{const{selectedValue,containerStyle,onChange}=props;return jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0},containerStyle],children:["weight",jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:selectedValue,onChange:value=>onChange(value),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"thin",label:"thin"}),jsxRuntimeExports.jsx(OptionItem,{value:"medium",label:"medium"}),jsxRuntimeExports.jsx(OptionItem,{value:"thick",label:"thick"})]})]})};
1614
1616
 
1615
- const{InfoTip: InfoTip$d}=components;function LockedFigureAria(props){const{ariaLabel,getPrepopulatedAriaLabel,onChangeProps}=props;const id=React.useId();const ariaLabelId=`aria-label-${id}`;const[loading,setLoading]=React.useState(false);return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:styles$t.row,children:[jsxRuntimeExports.jsx(LabelMedium,{tag:"label",htmlFor:ariaLabelId,children:"Aria label"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsxs(InfoTip$d,{children:["Aria label is used by screen readers to describe content to users who may be visually impaired. ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"Populating this field will make it so that users can use a screen reader to navigate to this point and hear the description.",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"If you leave this field blank, the point will be hidden from screen readers. Users will not be able to navigate to this point using a screen reader."]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(LabelXSmall,{style:styles$t.caption,children:"The figure is hidden from screen readers if this field is left blank."}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextArea,{id:ariaLabelId,value:loading?"Loading...":ariaLabel??"",onChange:newValue=>{onChangeProps({ariaLabel:newValue||undefined});},placeholder:"Ex. Point at (x, y)",rows:1,resizeType:"vertical"}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:pencilCircle,style:styles$t.button,onClick:()=>{setLoading(true);getPrepopulatedAriaLabel().then(ariaLabel=>{setLoading(false);onChangeProps({ariaLabel});});},children:"Auto-generate"})]})}const styles$t=StyleSheet.create({row:{flexDirection:"row",alignItems:"center"},button:{alignSelf:"start"},caption:{color:color.offBlack64}});
1617
+ const{InfoTip: InfoTip$c}=components;function LockedFigureAria(props){const{ariaLabel,getPrepopulatedAriaLabel,onChangeProps}=props;const id=React.useId();const ariaLabelId=`aria-label-${id}`;const[loading,setLoading]=React.useState(false);return jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:styles$t.row,children:[jsxRuntimeExports.jsx(LabelMedium,{tag:"label",htmlFor:ariaLabelId,children:"Aria label"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsxs(InfoTip$c,{children:["Aria label is used by screen readers to describe content to users who may be visually impaired. ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"Populating this field will make it so that users can use a screen reader to navigate to this point and hear the description.",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),"If you leave this field blank, the point will be hidden from screen readers. Users will not be able to navigate to this point using a screen reader."]})]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(LabelXSmall,{style:styles$t.caption,children:"The figure is hidden from screen readers if this field is left blank."}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(TextArea,{id:ariaLabelId,value:loading?"Loading...":ariaLabel??"",onChange:newValue=>{onChangeProps({ariaLabel:newValue||undefined});},placeholder:"Ex. Point at (x, y)",rows:1,resizeType:"vertical"}),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:pencilCircle,style:styles$t.button,onClick:()=>{setLoading(true);getPrepopulatedAriaLabel().then(ariaLabel=>{setLoading(false);onChangeProps({ariaLabel});});},children:"Auto-generate"})]})}const styles$t=StyleSheet.create({row:{flexDirection:"row",alignItems:"center"},button:{alignSelf:"start"},caption:{color:color.offBlack64}});
1616
1618
 
1617
1619
  const LockedFigureSettingsActions=props=>{const{figureType,onMove,onRemove}=props;return jsxRuntimeExports.jsxs(View,{style:styles$s.container,children:[jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,"aria-label":`Delete locked ${figureType}`,onClick:onRemove,kind:"tertiary",style:styles$s.deleteButton,children:"Delete"}),onMove&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(IconButton,{icon:caretDoubleUpIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} to the back`,onClick:()=>onMove("back")}),jsxRuntimeExports.jsx(IconButton,{icon:caretUpIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} backward`,onClick:()=>onMove("backward")}),jsxRuntimeExports.jsx(IconButton,{icon:caretDownIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} forward`,onClick:()=>onMove("forward")}),jsxRuntimeExports.jsx(IconButton,{icon:caretDoubleDownIcon,kind:"tertiary",size:"small","aria-label":`Move locked ${figureType} to the front`,onClick:()=>onMove("front")})]})]})};const styles$s=StyleSheet.create({container:{width:"100%",flexDirection:"row",alignItems:"center",marginTop:spacing.xxxSmall_4},deleteButton:{marginInlineStart:-spacing.xxxSmall_4}});
1618
1620
 
1619
- const{InfoTip: InfoTip$c}=components;function LockedLabelSettings(props){const{type,coord,color: color$1,size,text,expanded,onChangeProps,onMove,onRemove,onToggle,containerStyle}=props;return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:[styles$r.row,styles$r.accordionHeaderContainer],children:[jsxRuntimeExports.jsxs(LabelLarge,{children:["Label (",coord[0],", ",coord[1],")"]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),text!==""&&jsxRuntimeExports.jsx(LabelLarge,{style:[{backgroundColor:color.white,color:lockedFigureColors[color$1]},styles$r.accordionHeader],children:text})]}),containerStyle:containerStyle,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,onChange:newCoords=>{onChangeProps({coord:newCoords});},style:styles$r.spaceUnder}),jsxRuntimeExports.jsxs(View,{style:styles$r.row,children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$r.row,styles$r.spaceUnder,{flexGrow:1}],children:["text",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(TextField,{value:text,placeholder:"ex. $x^2$ or $\\frac{1}{2}$",onChange:newValue=>onChangeProps({text:newValue})})]}),jsxRuntimeExports.jsxs(InfoTip$c,{children:["Surround your text with $ for TeX.",jsxRuntimeExports.jsx("br",{}),"Example: ",`This circle has radius $\\frac{1}{2}$ units.`,jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),'It is important to use TeX when appropriate for accessibility. The above example would be read as "This circle has radius one-half units" by screen readers.']})]}),jsxRuntimeExports.jsxs(View,{style:styles$r.row,children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color$1,onChange:newColor=>{onChangeProps({color:newColor});},style:styles$r.spaceUnder}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$r.row,children:["size",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:size,onChange:newValue=>onChangeProps({size:newValue}),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"small",label:"small"}),jsxRuntimeExports.jsx(OptionItem,{value:"medium",label:"medium"}),jsxRuntimeExports.jsx(OptionItem,{value:"large",label:"large"})]})]})]}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:type,onMove:onMove,onRemove:onRemove})]})}const styles$r=StyleSheet.create({accordionHeaderContainer:{whiteSpace:"nowrap"},accordionHeader:{padding:spacing.xxxSmall_4,marginInlineEnd:spacing.xSmall_8,borderRadius:spacing.xxxSmall_4,textOverflow:"ellipsis",overflow:"hidden"},row:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0},spaceUnder:{marginBottom:spacing.xSmall_8}});
1621
+ const{InfoTip: InfoTip$b}=components;function LockedLabelSettings(props){const{type,coord,color: color$1,size,text,expanded,onChangeProps,onMove,onRemove,onToggle,containerStyle}=props;return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:[styles$r.row,styles$r.accordionHeaderContainer],children:[jsxRuntimeExports.jsxs(LabelLarge,{children:["Label (",coord[0],", ",coord[1],")"]}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),text!==""&&jsxRuntimeExports.jsx(LabelLarge,{style:[{backgroundColor:color.white,color:lockedFigureColors[color$1]},styles$r.accordionHeader],children:text})]}),containerStyle:containerStyle,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:coord,onChange:newCoords=>{onChangeProps({coord:newCoords});},style:styles$r.spaceUnder}),jsxRuntimeExports.jsxs(View,{style:styles$r.row,children:[jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$r.row,styles$r.spaceUnder,{flexGrow:1}],children:["text",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(TextField,{value:text,placeholder:"ex. $x^2$ or $\\frac{1}{2}$",onChange:newValue=>onChangeProps({text:newValue})})]}),jsxRuntimeExports.jsxs(InfoTip$b,{children:["Surround your text with $ for TeX.",jsxRuntimeExports.jsx("br",{}),"Example: ",`This circle has radius $\\frac{1}{2}$ units.`,jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("br",{}),'It is important to use TeX when appropriate for accessibility. The above example would be read as "This circle has radius one-half units" by screen readers.']})]}),jsxRuntimeExports.jsxs(View,{style:styles$r.row,children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color$1,onChange:newColor=>{onChangeProps({color:newColor});},style:styles$r.spaceUnder}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:styles$r.row,children:["size",jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(SingleSelect,{selectedValue:size,onChange:newValue=>onChangeProps({size:newValue}),placeholder:"",children:[jsxRuntimeExports.jsx(OptionItem,{value:"small",label:"small"}),jsxRuntimeExports.jsx(OptionItem,{value:"medium",label:"medium"}),jsxRuntimeExports.jsx(OptionItem,{value:"large",label:"large"})]})]})]}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:type,onMove:onMove,onRemove:onRemove})]})}const styles$r=StyleSheet.create({accordionHeaderContainer:{whiteSpace:"nowrap"},accordionHeader:{padding:spacing.xxxSmall_4,marginInlineEnd:spacing.xSmall_8,borderRadius:spacing.xxxSmall_4,textOverflow:"ellipsis",overflow:"hidden"},row:{display:"flex",flexDirection:"row",alignItems:"center",minWidth:0},spaceUnder:{marginBottom:spacing.xSmall_8}});
1620
1622
 
1621
1623
  const DEFAULT_COLOR="grayH";function getDefaultFigureForType(type){switch(type){case "point":return {type:"point",coord:[0,0],color:DEFAULT_COLOR,filled:true,labels:[]};case "line":return {type:"line",kind:"line",points:[getDefaultFigureForType("point"),{...getDefaultFigureForType("point"),coord:[2,2]}],color:DEFAULT_COLOR,lineStyle:"solid",showPoint1:false,showPoint2:false,weight:"medium",labels:[]};case "vector":return {type:"vector",points:[[0,0],[2,2]],color:DEFAULT_COLOR,weight:"medium",labels:[]};case "ellipse":return {type:"ellipse",center:[0,0],radius:[1,1],angle:0,color:DEFAULT_COLOR,fillStyle:"none",strokeStyle:"solid",weight:"medium",labels:[]};case "polygon":return {type:"polygon",points:[[0,2],[-1,0],[1,0]],color:DEFAULT_COLOR,showVertices:false,fillStyle:"none",strokeStyle:"solid",weight:"medium",labels:[]};case "function":return {type:"function",color:DEFAULT_COLOR,strokeStyle:"solid",weight:"medium",equation:"x^2",domain:[-Infinity,Infinity],directionalAxis:"x",labels:[]};case "label":return {type:"label",coord:[0,0],text:"label",color:DEFAULT_COLOR,size:"medium"};default:throw new UnreachableCaseError(type)}}function generateLockedFigureAppearanceDescription(color,strokeStyle="solid",fill,weight="medium"){const convertedColor=color==="grayH"?"gray":color;const weightString=weight==="medium"?"":` ${weight}`;const baseAppearance=`. Appearance${weightString} ${strokeStyle} ${convertedColor}`;switch(fill){case "none":return `${baseAppearance} border, with no fill.`;case "white":return `${baseAppearance} border, with a white fill.`;case "solid":case "translucent":return `${baseAppearance} border, with a ${fill} ${convertedColor} fill.`;case undefined:return `${baseAppearance}.`;default:throw new UnreachableCaseError(fill)}}async function generateSpokenMathDetails(mathString){const engine=await SpeechRuleEngine.setup("en");let convertedSpeech="";const parsedContent=mathOnlyParser(mathString);for(const piece of parsedContent){switch(piece.type){case "math":convertedSpeech+=engine.texToSpeech(piece.content);break;case "specialCharacter":convertedSpeech+=piece.content.length>1?piece.content.slice(1):piece.content;break;default:convertedSpeech+=piece.content;break}}return convertedSpeech}async function joinLabelsAsSpokenMath(labels){if(labels.length===0){return ""}const spokenLabelPromises=labels.map(label=>{return generateSpokenMathDetails(label.text)});const spokenLabels=await Promise.all(spokenLabelPromises);return ` ${spokenLabels.join(", ")}`}
1622
1624
 
1623
- const{convertRadiansToDegrees}=angles;const{InfoTip: InfoTip$b}=components;const LockedEllipseSettings=props=>{const{center,radius,angle,color,labels,ariaLabel,fillStyle,strokeStyle,weight,expanded,onToggle,onChangeProps,onMove,onRemove}=props;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenCenterX=await generateSpokenMathDetails(`$${center[0]}$`);const spokenCenterY=await generateSpokenMathDetails(`$${center[1]}$`);const spokenRotation=await generateSpokenMathDetails(`$${convertRadiansToDegrees(angle)}$`);const isCircle=radius[0]===radius[1];let str="";if(isCircle){str+=`Circle${visiblelabel} with radius ${radius[0]}`;}else {str+=`Ellipse${visiblelabel} with x radius ${radius[0]} and y radius ${radius[1]}`;}str+=`, centered at ${spokenCenterX} comma ${spokenCenterY}`;if(!isCircle&&angle!==0){str+=`, rotated by ${spokenRotation} degrees`;}const ellipseAppearance=generateLockedFigureAppearanceDescription(color,strokeStyle,fillStyle,weight);str+=ellipseAppearance;return str}function handleCenterChange(newCoord){const xOffset=newCoord[0]-center[0];const yOffset=newCoord[1]-center[1];const newProps={center:newCoord};newProps.labels=labels.map(label=>({...label,coord:[label.coord[0]+xOffset,label.coord[1]+yOffset]}));onChangeProps(newProps);}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$q.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(EllipseSwatch,{color:props.color,fillStyle:fillStyle,strokeStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:styles$q.row,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:center,style:styles$q.spaceUnder,onChange:handleCenterChange}),jsxRuntimeExports.jsx(View,{style:styles$q.spaceUnder,children:jsxRuntimeExports.jsx(InfoTip$b,{children:"The coordinates for the center of the ellipse."})})]}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:radius,labels:["x radius","y radius"],style:styles$q.spaceUnder,onChange:newCoords=>onChangeProps({radius:newCoords})}),jsxRuntimeExports.jsx(AngleInput,{angle:angle,onChange:newAngle=>onChangeProps({angle:newAngle})}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:[styles$q.row,styles$q.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$q.row,styles$q.truncatedWidth],children:["fill",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:fillStyle,onChange:value=>onChangeProps({fillStyle:value}),placeholder:"",children:Object.keys(lockedFigureFillStyles).map(option=>jsxRuntimeExports.jsx(OptionItem,{value:option,label:option},option))})]})]}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:value=>onChangeProps({strokeStyle:value}),containerStyle:{marginBottom:sizing.size_080}}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$q.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$q.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$q.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[center[0],center[1]-labels.length],color:color};onChangeProps({labels:[...labels,newLabel]});},style:styles$q.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$q=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},truncatedWidth:{minWidth:0},addButton:{alignSelf:"start"},labelContainer:{backgroundColor:color.white},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1625
+ const{convertRadiansToDegrees}=angles;const{InfoTip: InfoTip$a}=components;const LockedEllipseSettings=props=>{const{center,radius,angle,color,labels,ariaLabel,fillStyle,strokeStyle,weight,expanded,onToggle,onChangeProps,onMove,onRemove}=props;async function getPrepopulatedAriaLabel(){const visiblelabel=await joinLabelsAsSpokenMath(labels);const spokenCenterX=await generateSpokenMathDetails(`$${center[0]}$`);const spokenCenterY=await generateSpokenMathDetails(`$${center[1]}$`);const spokenRotation=await generateSpokenMathDetails(`$${convertRadiansToDegrees(angle)}$`);const isCircle=radius[0]===radius[1];let str="";if(isCircle){str+=`Circle${visiblelabel} with radius ${radius[0]}`;}else {str+=`Ellipse${visiblelabel} with x radius ${radius[0]} and y radius ${radius[1]}`;}str+=`, centered at ${spokenCenterX} comma ${spokenCenterY}`;if(!isCircle&&angle!==0){str+=`, rotated by ${spokenRotation} degrees`;}const ellipseAppearance=generateLockedFigureAppearanceDescription(color,strokeStyle,fillStyle,weight);str+=ellipseAppearance;return str}function handleCenterChange(newCoord){const xOffset=newCoord[0]-center[0];const yOffset=newCoord[1]-center[1];const newProps={center:newCoord};newProps.labels=labels.map(label=>({...label,coord:[label.coord[0]+xOffset,label.coord[1]+yOffset]}));onChangeProps(newProps);}function handleColorChange(newValue){const newProps={color:newValue};newProps.labels=labels.map(label=>({...label,color:newValue}));onChangeProps(newProps);}function handleLabelChange(updatedLabel,labelIndex){const updatedLabels=[...labels];updatedLabels[labelIndex]={...labels[labelIndex],...updatedLabel};onChangeProps({labels:updatedLabels});}function handleLabelRemove(labelIndex){const updatedLabels=labels.filter((_,index)=>index!==labelIndex);onChangeProps({labels:updatedLabels});}return jsxRuntimeExports.jsxs(PerseusEditorAccordion,{expanded:expanded,onToggle:onToggle,header:jsxRuntimeExports.jsxs(View,{style:styles$q.row,children:[jsxRuntimeExports.jsx(LabelLarge,{children:`Ellipse (${center[0]}, ${center[1]}), radius ${radius[0]}, ${radius[1]}`}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsx(EllipseSwatch,{color:props.color,fillStyle:fillStyle,strokeStyle:strokeStyle})]}),children:[jsxRuntimeExports.jsxs(View,{style:styles$q.row,children:[jsxRuntimeExports.jsx(CoordinatePairInput,{coord:center,style:styles$q.spaceUnder,onChange:handleCenterChange}),jsxRuntimeExports.jsx(View,{style:styles$q.spaceUnder,children:jsxRuntimeExports.jsx(InfoTip$a,{children:"The coordinates for the center of the ellipse."})})]}),jsxRuntimeExports.jsx(CoordinatePairInput,{coord:radius,labels:["x radius","y radius"],style:styles$q.spaceUnder,onChange:newCoords=>onChangeProps({radius:newCoords})}),jsxRuntimeExports.jsx(AngleInput,{angle:angle,onChange:newAngle=>onChangeProps({angle:newAngle})}),jsxRuntimeExports.jsx(Strut,{size:spacing.xSmall_8}),jsxRuntimeExports.jsxs(View,{style:[styles$q.row,styles$q.spaceUnder],children:[jsxRuntimeExports.jsx(ColorSelect,{selectedValue:color,onChange:handleColorChange}),jsxRuntimeExports.jsx(Strut,{size:spacing.medium_16}),jsxRuntimeExports.jsxs(LabelMedium,{tag:"label",style:[styles$q.row,styles$q.truncatedWidth],children:["fill",jsxRuntimeExports.jsx(Strut,{size:spacing.xxSmall_6}),jsxRuntimeExports.jsx(SingleSelect,{selectedValue:fillStyle,onChange:value=>onChangeProps({fillStyle:value}),placeholder:"",children:Object.keys(lockedFigureFillStyles).map(option=>jsxRuntimeExports.jsx(OptionItem,{value:option,label:option},option))})]})]}),jsxRuntimeExports.jsx(LineStrokeSelect,{selectedValue:strokeStyle,onChange:value=>onChangeProps({strokeStyle:value}),containerStyle:{marginBottom:sizing.size_080}}),jsxRuntimeExports.jsx(LineWeightSelect,{selectedValue:weight,onChange:value=>onChangeProps({weight:value})}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(View,{style:styles$q.horizontalRule}),jsxRuntimeExports.jsx(LockedFigureAria,{ariaLabel:ariaLabel,getPrepopulatedAriaLabel:getPrepopulatedAriaLabel,onChangeProps:newProps=>{onChangeProps(newProps);}}),jsxRuntimeExports.jsx(Strut,{size:spacing.xxxSmall_4}),jsxRuntimeExports.jsx(View,{style:styles$q.horizontalRule}),jsxRuntimeExports.jsx(Strut,{size:spacing.small_12}),jsxRuntimeExports.jsx(LabelMedium,{children:"Visible labels"}),labels.map((label,labelIndex)=>createElement(LockedLabelSettings,{...label,key:labelIndex,expanded:true,onChangeProps:newLabel=>{handleLabelChange(newLabel,labelIndex);},onRemove:()=>{handleLabelRemove(labelIndex);},containerStyle:styles$q.labelContainer})),jsxRuntimeExports.jsx(Button,{kind:"tertiary",startIcon:plusCircle,onClick:()=>{const newLabel={...getDefaultFigureForType("label"),coord:[center[0],center[1]-labels.length],color:color};onChangeProps({labels:[...labels,newLabel]});},style:styles$q.addButton,children:"Add visible label"}),jsxRuntimeExports.jsx(LockedFigureSettingsActions,{figureType:props.type,onMove:onMove,onRemove:onRemove})]})};const styles$q=StyleSheet.create({row:{display:"flex",flexDirection:"row",alignItems:"center"},spaceUnder:{marginBottom:spacing.xSmall_8},truncatedWidth:{minWidth:0},addButton:{alignSelf:"start"},labelContainer:{backgroundColor:color.white},horizontalRule:{height:1,backgroundColor:color.offBlack16}});
1624
1626
 
1625
1627
  const LineSwatch=props=>{const{color,lineStyle}=props;return jsxRuntimeExports.jsx(View,{style:styles$p.container,children:jsxRuntimeExports.jsx(View,{"aria-label":`${color}, ${lineStyle}`,style:[styles$p.lineSwatch,{border:`5px ${lineStyle} ${lockedFigureColors[color]}`}]})})};const styles$p=StyleSheet.create({container:{backgroundColor:color.white,justifyContent:"center",padding:spacing.xSmall_8,borderRadius:spacing.xxxSmall_4},lineSwatch:{width:40}});
1626
1628
 
@@ -1696,40 +1698,40 @@ const SelectImage=({onChange,url})=>jsxRuntimeExports.jsxs("div",{children:[jsxR
1696
1698
 
1697
1699
  class LabelImageEditor extends React.Component{componentDidUpdate(prevProps){const coordsToMarkers={};prevProps.markers.forEach(marker=>coordsToMarkers[`${marker.x}.${marker.y}`]=marker);const newIndices=this.props.markers.map((marker,index)=>coordsToMarkers.hasOwnProperty(`${marker.x}.${marker.y}`)?-1:index).filter(index=>index!==-1);if(newIndices.length&&this._questionMarkers){this._questionMarkers.openDropdownForMarkerIndices(newIndices);}}serialize(){return EditorJsonify.serialize.call(this)}render(){const{choices,imageAlt,imageUrl,imageWidth,imageHeight,markers,multipleAnswers,hideChoicesFromInstructions,preferredPopoverDirection}=this.props;const editingDisabled=this.props.apiOptions?.editingDisabled??false;const imageSelected=imageUrl&&imageWidth>0&&imageHeight>0;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(SelectImage,{onChange:this.handleImageChange,url:imageUrl}),jsxRuntimeExports.jsx("div",{className:css(styles$1.smallSpacer)}),imageSelected&&jsxRuntimeExports.jsx(FormWrappedTextField$1,{placeholder:"Alt text (for screen readers)",onChange:e=>this.handleAltChange(e.target.value),value:imageAlt,width:"100%"}),jsxRuntimeExports.jsx("div",{className:css(styles$1.largeSpacer)}),jsxRuntimeExports.jsx(QuestionMarkers,{editingDisabled:editingDisabled,choices:choices,imageUrl:imageSelected?imageUrl:"",imageWidth:imageWidth,imageHeight:imageHeight,markers:markers,onChange:this.handleMarkersChange,ref:node=>this._questionMarkers=node}),jsxRuntimeExports.jsx("div",{className:css(styles$1.largeSpacer)}),jsxRuntimeExports.jsx(AnswerChoices,{choices:choices,editingDisabled:editingDisabled,onChange:this.handleChoicesChange}),jsxRuntimeExports.jsx("div",{className:css(styles$1.largeSpacer)}),jsxRuntimeExports.jsx(Behavior,{preferredPopoverDirection:preferredPopoverDirection,multipleAnswers:multipleAnswers,hideChoicesFromInstructions:hideChoicesFromInstructions,onChange:this.handleBehaviorChange})]})}constructor(...args){super(...args),this.getSaveWarnings=()=>{const{choices,imageAlt,imageUrl,markers}=this.props;const warnings=[];if(choices.length<2){warnings.push("Question requires at least two answer choices");}if(!imageUrl){warnings.push("Image is not specified for question");}else if(!imageAlt){warnings.push("Question image has no alt text");}if(!markers.length){warnings.push("Question has no markers, to label answers on image");}else {let numNoAnswers=0;let numNoLabels=0;for(const marker of markers){if(!marker.answers.length){numNoAnswers++;}if(!marker.label){numNoLabels++;}}if(numNoAnswers){warnings.push(`Question has ${numNoAnswers} markers with no `+"answers selected");}if(numNoLabels){warnings.push(`Question has ${numNoLabels} markers with no `+"ARIA label");}}return warnings},this.handleImageChange=url=>{this.props.onChange({imageUrl:url,imageWidth:0,imageHeight:0});if(url){Util.getImageSize(url,(width,height)=>{this.props.onChange({imageUrl:url,imageWidth:width,imageHeight:height});});}},this.handleAltChange=alt=>{this.props.onChange({imageAlt:alt});},this.handleChoicesChange=choices=>{this.props.onChange({choices});},this.handleMarkersChange=markers=>{this.props.onChange({markers});},this.handleBehaviorChange=options=>{this.props.onChange(options);};}}LabelImageEditor.defaultProps=labelImageLogic.defaultWidgetOptions;LabelImageEditor.widgetName="label-image";const styles$1=StyleSheet.create({largeSpacer:{height:32},smallSpacer:{height:16}});
1698
1700
 
1699
- const{InfoTip: InfoTip$a,TextListEditor: TextListEditor$3}=components;class MatcherEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-matcher-editor",children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$a,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answers here. The preview on the right will show the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-clearfix",children:[jsxRuntimeExports.jsx(TextListEditor$3,{options:this.props.left,onChange:(options,cb)=>{this.props.onChange({left:options},cb);},layout:"vertical"}),jsxRuntimeExports.jsx(TextListEditor$3,{options:this.props.right,onChange:(options,cb)=>{this.props.onChange({right:options},cb);},layout:"vertical"})]}),jsxRuntimeExports.jsxs("span",{children:[" ","Labels:"," ",jsxRuntimeExports.jsx(InfoTip$a,{children:jsxRuntimeExports.jsx("p",{children:"These are entirely optional."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[0],onChange:this.onLabelChange.bind(this,0)}),jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[1],onChange:this.onLabelChange.bind(this,1)})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Order of the matched pairs matters:",checked:this.props.orderMatters,onChange:value=>{this.props.onChange({orderMatters:value});}}),jsxRuntimeExports.jsxs(InfoTip$a,{children:[jsxRuntimeExports.jsx("p",{children:"With this option enabled, only the order provided above will be treated as correct. This is useful when ordering is significant, such as in the context of a proof."}),jsxRuntimeExports.jsx("p",{children:"If disabled, pairwise matching is sufficient. To make this clear, the left column becomes fixed in the provided order and only the cards in the right column can be moved."})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip$a,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLabelChange=(index,e)=>{const labels=_.clone(this.props.labels);labels[index]=e.target.value;this.props.onChange({labels:labels});},this.getSaveWarnings=()=>{if(this.props.left.length!==this.props.right.length){return ["The two halves of the matcher have different numbers"+" of cards."]}return []},this.serialize=()=>{return _.pick(this.props,"left","right","labels","orderMatters","padding")};}}MatcherEditor.propTypes={left:PropTypes.array,right:PropTypes.array,labels:PropTypes.array,orderMatters:PropTypes.bool,padding:PropTypes.bool};MatcherEditor.widgetName="matcher";MatcherEditor.defaultProps=matcherLogic.defaultWidgetOptions;
1701
+ const{InfoTip: InfoTip$9,TextListEditor: TextListEditor$3}=components;class MatcherEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-matcher-editor",children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$9,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answers here. The preview on the right will show the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-clearfix",children:[jsxRuntimeExports.jsx(TextListEditor$3,{options:this.props.left,onChange:(options,cb)=>{this.props.onChange({left:options},cb);},layout:"vertical"}),jsxRuntimeExports.jsx(TextListEditor$3,{options:this.props.right,onChange:(options,cb)=>{this.props.onChange({right:options},cb);},layout:"vertical"})]}),jsxRuntimeExports.jsxs("span",{children:[" ","Labels:"," ",jsxRuntimeExports.jsx(InfoTip$9,{children:jsxRuntimeExports.jsx("p",{children:"These are entirely optional."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[0],onChange:this.onLabelChange.bind(this,0)}),jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.labels[1],onChange:this.onLabelChange.bind(this,1)})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Order of the matched pairs matters:",checked:this.props.orderMatters,onChange:value=>{this.props.onChange({orderMatters:value});}}),jsxRuntimeExports.jsxs(InfoTip$9,{children:[jsxRuntimeExports.jsx("p",{children:"With this option enabled, only the order provided above will be treated as correct. This is useful when ordering is significant, such as in the context of a proof."}),jsxRuntimeExports.jsx("p",{children:"If disabled, pairwise matching is sufficient. To make this clear, the left column becomes fixed in the provided order and only the cards in the right column can be moved."})]})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip$9,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLabelChange=(index,e)=>{const labels=_.clone(this.props.labels);labels[index]=e.target.value;this.props.onChange({labels:labels});},this.getSaveWarnings=()=>{if(this.props.left.length!==this.props.right.length){return ["The two halves of the matcher have different numbers"+" of cards."]}return []},this.serialize=()=>{return _.pick(this.props,"left","right","labels","orderMatters","padding")};}}MatcherEditor.propTypes={left:PropTypes.array,right:PropTypes.array,labels:PropTypes.array,orderMatters:PropTypes.bool,padding:PropTypes.bool};MatcherEditor.widgetName="matcher";MatcherEditor.defaultProps=matcherLogic.defaultWidgetOptions;
1700
1702
 
1701
1703
  const{RangeInput: RangeInput$3}=components;const Matrix=MatrixWidget.widget;const MAX_BOARD_SIZE=6;class MatrixEditor extends React.Component{render(){const matrixProps={onBlur:()=>{},onFocus:()=>{},trackInteraction:()=>{},userInput:{answers:this.props.answers},handleUserInput:userInput=>{this.change({answers:userInput.answers});},...this.props};return jsxRuntimeExports.jsxs("div",{className:"perseus-matrix-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Max matrix size:"," ",jsxRuntimeExports.jsx(RangeInput$3,{value:this.props.matrixBoardSize,onChange:this.onMatrixBoardSizeChange,format:this.props.labelStyle,useArrowKeys:true})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Matrix,{...matrixProps})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Matrix prefix:"," ",jsxRuntimeExports.jsx(Editor,{ref:"prefix",apiOptions:this.props.apiOptions,content:this.props.prefix,widgetEnabled:false,onChange:newProps=>{this.change({prefix:newProps.content});}})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[" ","Matrix suffix:"," ",jsxRuntimeExports.jsx(Editor,{ref:"suffix",apiOptions:this.props.apiOptions,content:this.props.suffix,widgetEnabled:false,onChange:newProps=>{this.change({suffix:newProps.content});}})]})]})}constructor(...args){super(...args),this.change=(...args)=>{if(this.props.apiOptions.editingDisabled){return}return Changeable.change.apply(this,args)},this.onMatrixBoardSizeChange=range=>{const matrixSize=getMatrixSize(this.props.answers);if(range[0]!==null&&range[1]!==null){range=[Math.round(Math.min(Math.max(range[0],1),MAX_BOARD_SIZE)),Math.round(Math.min(Math.max(range[1],1),MAX_BOARD_SIZE))];const answers=_(Math.min(range[0],matrixSize[0])).times(row=>{return _(Math.min(range[1],matrixSize[1])).times(col=>{return this.props.answers[row][col]})});this.props.onChange({matrixBoardSize:range,answers:answers});}},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MatrixEditor.propTypes={...Changeable.propTypes,matrixBoardSize:PropTypes.arrayOf(PropTypes.number).isRequired,answers:PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)),prefix:PropTypes.string,suffix:PropTypes.string,cursorPosition:PropTypes.arrayOf(PropTypes.number)};MatrixEditor.widgetName="matrix";MatrixEditor.defaultProps=matrixLogic.defaultWidgetOptions;
1702
1704
 
1703
- const{InfoTip: InfoTip$9,NumberInput: NumberInput$7,RangeInput: RangeInput$2}=components;const defaultImage={url:null,top:0,left:0};class MeasurerEditor extends React.Component{render(){const image=_.extend({},defaultImage,this.props.image);return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-measurer",children:[jsxRuntimeExports.jsx("div",{children:"Image displayed under protractor and/or ruler:"}),jsxRuntimeExports.jsxs("div",{children:["URL:"," ",jsxRuntimeExports.jsx("input",{type:"text",className:"perseus-widget-measurer-url",ref:"image-url",defaultValue:image.url,onChange:this._changeUrl}),jsxRuntimeExports.jsx(InfoTip$9,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),image.url&&jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{className:"perseus-widget-left-col",children:["Pixels from top:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:0,onChange:this._changeTop,value:image.top,useArrowKeys:true})]}),jsxRuntimeExports.jsxs("label",{className:"perseus-widget-right-col",children:["Pixels from left:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:0,onChange:this._changeLeft,value:image.left,useArrowKeys:true})]})]}),jsxRuntimeExports.jsxs("div",{children:["Containing area [width, height]:"," ",jsxRuntimeExports.jsx(RangeInput$2,{onChange:this.change("box"),value:this.props.box,useArrowKeys:true})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.props.onChange({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.props.onChange({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:e=>this.change("rulerLabel",e.target.value),value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:e=>this.change("rulerTicks",+e.target.value),value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler pixels per unit:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:40,onChange:this.change("rulerPixels"),value:this.props.rulerPixels,useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler length in units:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:10,onChange:this.change("rulerLength"),value:this.props.rulerLength,useArrowKeys:true})]})})]})]})}constructor(...args){super(...args),this.className="perseus-widget-measurer",this.change=(...args)=>{return Changeable.change.apply(this,args)},this._changeUrl=e=>{this._changeImage("url",e.target.value);},this._changeTop=newTop=>{this._changeImage("top",newTop);},this._changeLeft=newLeft=>{this._changeImage("left",newLeft);},this._changeImage=(subProp,newValue)=>{const image=_.clone(this.props.image);image[subProp]=newValue;this.change("image",image);},this.renderLabelChoices=choices=>{return _.map(choices,function(nameAndValue){const[name,value]=nameAndValue;return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MeasurerEditor.widgetName="measurer";MeasurerEditor.propTypes={...Changeable.propTypes,box:PropTypes.arrayOf(PropTypes.number),image:PropTypes.shape({url:PropTypes.string,top:PropTypes.number,left:PropTypes.number}),showProtractor:PropTypes.bool,showRuler:PropTypes.bool,rulerLabel:PropTypes.string,rulerTicks:PropTypes.number,rulerPixels:PropTypes.number,rulerLength:PropTypes.number};MeasurerEditor.defaultProps=measurerLogic.defaultWidgetOptions;
1705
+ const{InfoTip: InfoTip$8,NumberInput: NumberInput$7,RangeInput: RangeInput$2}=components;const defaultImage={url:null,top:0,left:0};class MeasurerEditor extends React.Component{render(){const image=_.extend({},defaultImage,this.props.image);return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-measurer",children:[jsxRuntimeExports.jsx("div",{children:"Image displayed under protractor and/or ruler:"}),jsxRuntimeExports.jsxs("div",{children:["URL:"," ",jsxRuntimeExports.jsx("input",{type:"text",className:"perseus-widget-measurer-url",ref:"image-url",defaultValue:image.url,onChange:this._changeUrl}),jsxRuntimeExports.jsx(InfoTip$8,{children:jsxRuntimeExports.jsx("p",{children:'Create an image in graphie, or use the "Add image" function to create a background.'})})]}),image.url&&jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{className:"perseus-widget-left-col",children:["Pixels from top:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:0,onChange:this._changeTop,value:image.top,useArrowKeys:true})]}),jsxRuntimeExports.jsxs("label",{className:"perseus-widget-right-col",children:["Pixels from left:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:0,onChange:this._changeLeft,value:image.left,useArrowKeys:true})]})]}),jsxRuntimeExports.jsxs("div",{children:["Containing area [width, height]:"," ",jsxRuntimeExports.jsx(RangeInput$2,{onChange:this.change("box"),value:this.props.box,useArrowKeys:true})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show ruler",checked:this.props.showRuler,onChange:value=>{this.props.onChange({showRuler:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show protractor",checked:this.props.showProtractor,onChange:value=>{this.props.onChange({showProtractor:value});}})})]}),this.props.showRuler&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler label:"," ",jsxRuntimeExports.jsxs("select",{onChange:e=>this.change("rulerLabel",e.target.value),value:this.props.rulerLabel,children:[jsxRuntimeExports.jsx("option",{value:"",children:"None"}),jsxRuntimeExports.jsx("optgroup",{label:"Metric",children:this.renderLabelChoices([["milimeters","mm"],["centimeters","cm"],["meters","m"],["kilometers","km"]])}),jsxRuntimeExports.jsx("optgroup",{label:"Imperial",children:this.renderLabelChoices([["inches","in"],["feet","ft"],["yards","yd"],["miles","mi"]])})]})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:[" ","Ruler ticks:"," ",jsxRuntimeExports.jsx("select",{onChange:e=>this.change("rulerTicks",+e.target.value),value:this.props.rulerTicks,children:_.map([1,2,4,8,10,16],function(n){return jsxRuntimeExports.jsx("option",{value:n,children:n},n)})})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler pixels per unit:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:40,onChange:this.change("rulerPixels"),value:this.props.rulerPixels,useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Ruler length in units:"," ",jsxRuntimeExports.jsx(NumberInput$7,{placeholder:10,onChange:this.change("rulerLength"),value:this.props.rulerLength,useArrowKeys:true})]})})]})]})}constructor(...args){super(...args),this.className="perseus-widget-measurer",this.change=(...args)=>{return Changeable.change.apply(this,args)},this._changeUrl=e=>{this._changeImage("url",e.target.value);},this._changeTop=newTop=>{this._changeImage("top",newTop);},this._changeLeft=newLeft=>{this._changeImage("left",newLeft);},this._changeImage=(subProp,newValue)=>{const image=_.clone(this.props.image);image[subProp]=newValue;this.change("image",image);},this.renderLabelChoices=choices=>{return _.map(choices,function(nameAndValue){const[name,value]=nameAndValue;return jsxRuntimeExports.jsx("option",{value:value,children:name},value)})},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MeasurerEditor.widgetName="measurer";MeasurerEditor.propTypes={...Changeable.propTypes,box:PropTypes.arrayOf(PropTypes.number),image:PropTypes.shape({url:PropTypes.string,top:PropTypes.number,left:PropTypes.number}),showProtractor:PropTypes.bool,showRuler:PropTypes.bool,rulerLabel:PropTypes.string,rulerTicks:PropTypes.number,rulerPixels:PropTypes.number,rulerLength:PropTypes.number};MeasurerEditor.defaultProps=measurerLogic.defaultWidgetOptions;
1704
1706
 
1705
1707
  const{NumberInput: NumberInput$6,TextInput: TextInput$3}=components;class MoleculeWidgetEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["SMILES: ",jsxRuntimeExports.jsx(TextInput$3,{onChange:this.updateMolecule,value:this.props.smiles})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Rotation (deg): ",jsxRuntimeExports.jsx(NumberInput$6,{onChange:this.updateRotation,value:this.props.rotationAngle})]})})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.updateMolecule=newValue=>{this.change({smiles:newValue});},this.updateRotation=newValue=>{this.change({rotationAngle:newValue});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}MoleculeWidgetEditor.propTypes={...Changeable.propTypes,rotationAngle:PropTypes.number,smiles:PropTypes.string};MoleculeWidgetEditor.widgetName="molecule-renderer";
1706
1708
 
1707
- const{ButtonGroup,InfoTip: InfoTip$8,NumberInput: NumberInput$5,RangeInput: RangeInput$1}=components;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";class NumberLineEditor extends React.Component{render(){const range=this.props.range;const labelRange=this.props.labelRange;const divisionRange=this.props.divisionRange;range[0]=+range[0];range[1]=+range[1];const width=range[1]-range[0];const numDivisions=this.props.numDivisions;const snapDivisions=this.props.snapDivisions;const tickStep=this.props.tickStep;const isTickCtrl=this.props.isTickCtrl;let step;if(!isTickCtrl){step=tickStep?tickStep/snapDivisions:width/numDivisions/snapDivisions;}else {step=null;}const labelStyleEditorButtons=[{value:"decimal",content:"0.75",title:"Decimals"},{value:"improper",content:"⁷⁄₄",title:"Improper fractions"},{value:"mixed",content:"1¾",title:"Mixed numbers"},{value:"non-reduced",content:"⁸⁄₄",title:"Non-reduced"}];return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-number-line-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Correct x"," ",jsxRuntimeExports.jsxs("select",{value:this.props.correctRel,onChange:this.onChangeRelation,"aria-label":"Select relationship",children:[jsxRuntimeExports.jsx("option",{value:"eq","aria-label":"Equal",children:"="}),jsxRuntimeExports.jsx("option",{value:"lt","aria-label":"Less than",children:"<"}),jsxRuntimeExports.jsx("option",{value:"gt","aria-label":"Greater than",children:">"}),jsxRuntimeExports.jsx("option",{value:"le","aria-label":"Less than or equal",children:"≤"}),jsxRuntimeExports.jsx("option",{value:"ge","aria-label":"Greater than or equal",children:"≥"})]})," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.correctX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"correctX"),checkValidity:val=>val>=range[0]&&val<=range[1]&&(!step||number.isInteger((val-range[0])/step)),placeholder:"answer",size:"normal",useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip$8,{children:jsxRuntimeExports.jsx("p",{children:"This is the correct answer. The answer is validated (as right or wrong) by using only the end position of the point and the relation (=, <, >, ≤, ≥)."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[this.props.static?jsxRuntimeExports.jsx("label",{children:"Range:"}):jsxRuntimeExports.jsxs("label",{children:["Position:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.initialX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"initialX"),placeholder:range[0],checkValidity:val=>{return val>=range[0]&&val<=range[1]},useArrowKeys:true})," ∈ "]}),jsxRuntimeExports.jsx(RangeInput$1,{value:range,onChange:this.onRangeChange,format:this.props.labelStyle,useArrowKeys:true}),jsxRuntimeExports.jsxs(InfoTip$8,{children:[jsxRuntimeExports.jsxs("p",{children:["This controls the initial position of the point along the number line and the",jsxRuntimeExports.jsx("strong",{children:"range"}),", the position of the endpoints of the number line. Setting the range constrains the position of the answer and the labels."]}),jsxRuntimeExports.jsx("p",{children:"In static mode, the initial position of the point is determined by Correct x instead of position."})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:["Labels:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:labelRange[0],placeholder:range[0],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,0),useArrowKeys:true}),jsxRuntimeExports.jsx("span",{children:" & "}),jsxRuntimeExports.jsx(NumberInput$5,{value:labelRange[1],placeholder:range[1],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,1),useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip$8,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the position of the left / right labels. By default, the labels are set by the range ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," Ensure that the labels line up with the tick marks, or it may be confusing for users."]})})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Style:"," ",jsxRuntimeExports.jsx(ButtonGroup,{allowEmpty:false,value:this.props.labelStyle,buttons:labelStyleEditorButtons,onChange:this.onLabelStyleChange}),jsxRuntimeExports.jsx(InfoTip$8,{children:jsxRuntimeExports.jsx("p",{children:"This controls the styling of the labels for the two main labels as well as all the tick mark labels, if applicable. Your choices are decimal, improper fractions, mixed fractions, and non-reduced fractions."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[!this.props.static&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tick controller",checked:!!this.props.isTickCtrl,onChange:value=>{this.props.onChange({isTickCtrl:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show label ticks",checked:this.props.labelTicks,onChange:value=>{this.props.onChange({labelTicks:value});}})})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:!this.props.static&&jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.props.onChange({showTooltips:value});}})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Start num divisions at"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip$8,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks. The number of divisions is constrained to"," "+divisionRange[0]+EN_DASH+divisionRange[1],".",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," The user will be able to specify the number of divisions in a number input."]})})]}),!isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Num divisions:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]})," ",jsxRuntimeExports.jsxs("label",{children:["or tick step:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.tickStep||null,format:this.props.labelStyle,onChange:this.onTickStepChange,checkValidity:val=>{return val>0&&val<=width},placeholder:width/this.props.numDivisions,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip$8,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks; you can either set the number of divisions (2 divisions would split the entire range in two halves), or the tick step (the distance between ticks) and the other value will be updated accordingly."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," There is no check to see if labels coordinate with the tick marks, which may be confusing for users if the blue labels and black ticks are off-step."]})})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{children:["Snap increments per tick:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:snapDivisions,checkValidity:val=>val>0,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"snapDivisions"),useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip$8,{children:jsxRuntimeExports.jsxs("p",{children:["This determines the number of different places the point will snap between two adjacent tick marks."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"}),"Ensure the required number of snap increments is provided to answer the question."]})})]})]})}constructor(...args){super(...args),this.onRangeChange=range=>{this.props.onChange({range:range});},this.onLabelRangeChange=(i,num)=>{let labelRange=this.props.labelRange.slice();const otherNum=labelRange[1-i];if(num==null||otherNum==null){labelRange[i]=num;}else {labelRange=[Math.min(num,otherNum),Math.max(num,otherNum)];}this.props.onChange({labelRange:labelRange});},this.onDivisionRangeChange=divisionRange=>{let numDivisions=this.props.numDivisions;numDivisions=bound(numDivisions,divisionRange[0],divisionRange[1]);this.props.onChange({divisionRange:divisionRange,numDivisions:numDivisions});},this.onNumChange=(key,value)=>{const opts={};opts[key]=value;this.props.onChange(opts);},this.onNumDivisionsChange=numDivisions=>{const divRange=this.props.divisionRange.slice();numDivisions=_.isFinite(numDivisions)?Math.round(numDivisions):0;numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){numDivisions=Math.min(divRange[1],Math.max(divRange[0],numDivisions));this.props.onChange({tickStep:null,divisionRange:divRange,numDivisions:numDivisions});}},this.onTickStepChange=tickStep=>{this.props.onChange({numDivisions:null,tickStep:tickStep});},this.onChangeRelation=e=>{const value=e.target.value;this.props.onChange({correctRel:value,isInequality:value!=="eq"});},this.onLabelStyleChange=labelStyle=>{this.props.onChange({labelStyle:labelStyle});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}NumberLineEditor.widgetName="number-line";NumberLineEditor.defaultProps=numberLineLogic.defaultWidgetOptions;
1709
+ const{ButtonGroup,InfoTip: InfoTip$7,NumberInput: NumberInput$5,RangeInput: RangeInput$1}=components;const bound=(x,gt,lt)=>Math.min(Math.max(x,gt),lt);const EN_DASH="–";class NumberLineEditor extends React.Component{render(){const range=this.props.range;const labelRange=this.props.labelRange;const divisionRange=this.props.divisionRange;range[0]=+range[0];range[1]=+range[1];const width=range[1]-range[0];const numDivisions=this.props.numDivisions;const snapDivisions=this.props.snapDivisions;const tickStep=this.props.tickStep;const isTickCtrl=this.props.isTickCtrl;let step;if(!isTickCtrl){step=tickStep?tickStep/snapDivisions:width/numDivisions/snapDivisions;}else {step=null;}const labelStyleEditorButtons=[{value:"decimal",content:"0.75",title:"Decimals"},{value:"improper",content:"⁷⁄₄",title:"Improper fractions"},{value:"mixed",content:"1¾",title:"Mixed numbers"},{value:"non-reduced",content:"⁸⁄₄",title:"Non-reduced"}];return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-number-line-editor",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Correct x"," ",jsxRuntimeExports.jsxs("select",{value:this.props.correctRel,onChange:this.onChangeRelation,"aria-label":"Select relationship",children:[jsxRuntimeExports.jsx("option",{value:"eq","aria-label":"Equal",children:"="}),jsxRuntimeExports.jsx("option",{value:"lt","aria-label":"Less than",children:"<"}),jsxRuntimeExports.jsx("option",{value:"gt","aria-label":"Greater than",children:">"}),jsxRuntimeExports.jsx("option",{value:"le","aria-label":"Less than or equal",children:"≤"}),jsxRuntimeExports.jsx("option",{value:"ge","aria-label":"Greater than or equal",children:"≥"})]})," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.correctX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"correctX"),checkValidity:val=>val>=range[0]&&val<=range[1]&&(!step||number.isInteger((val-range[0])/step)),placeholder:"answer",size:"normal",useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsx("p",{children:"This is the correct answer. The answer is validated (as right or wrong) by using only the end position of the point and the relation (=, <, >, ≤, ≥)."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[this.props.static?jsxRuntimeExports.jsx("label",{children:"Range:"}):jsxRuntimeExports.jsxs("label",{children:["Position:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.initialX,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"initialX"),placeholder:range[0],checkValidity:val=>{return val>=range[0]&&val<=range[1]},useArrowKeys:true})," ∈ "]}),jsxRuntimeExports.jsx(RangeInput$1,{value:range,onChange:this.onRangeChange,format:this.props.labelStyle,useArrowKeys:true}),jsxRuntimeExports.jsxs(InfoTip$7,{children:[jsxRuntimeExports.jsxs("p",{children:["This controls the initial position of the point along the number line and the",jsxRuntimeExports.jsx("strong",{children:"range"}),", the position of the endpoints of the number line. Setting the range constrains the position of the answer and the labels."]}),jsxRuntimeExports.jsx("p",{children:"In static mode, the initial position of the point is determined by Correct x instead of position."})]})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("div",{className:"perseus-widget-left-col",children:["Labels:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:labelRange[0],placeholder:range[0],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,0),useArrowKeys:true}),jsxRuntimeExports.jsx("span",{children:" & "}),jsxRuntimeExports.jsx(NumberInput$5,{value:labelRange[1],placeholder:range[1],format:this.props.labelStyle,checkValidity:val=>val>=range[0]&&val<=range[1],onChange:this.onLabelRangeChange.bind(this,1),useArrowKeys:true}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the position of the left / right labels. By default, the labels are set by the range ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," Ensure that the labels line up with the tick marks, or it may be confusing for users."]})})]})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:["Style:"," ",jsxRuntimeExports.jsx(ButtonGroup,{allowEmpty:false,value:this.props.labelStyle,buttons:labelStyleEditorButtons,onChange:this.onLabelStyleChange}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsx("p",{children:"This controls the styling of the labels for the two main labels as well as all the tick mark labels, if applicable. Your choices are decimal, improper fractions, mixed fractions, and non-reduced fractions."})})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[!this.props.static&&jsxRuntimeExports.jsx("div",{className:"perseus-widget-left-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tick controller",checked:!!this.props.isTickCtrl,onChange:value=>{this.props.onChange({isTickCtrl:value});}})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-right-col",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show label ticks",checked:this.props.labelTicks,onChange:value=>{this.props.onChange({labelTicks:value});}})})]}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:!this.props.static&&jsxRuntimeExports.jsx(Checkbox$1,{label:"Show tooltips",checked:this.props.showTooltips,onChange:value=>{this.props.onChange({showTooltips:value});}})}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Start num divisions at"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks. The number of divisions is constrained to"," "+divisionRange[0]+EN_DASH+divisionRange[1],".",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," The user will be able to specify the number of divisions in a number input."]})})]}),!isTickCtrl&&jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsxs("label",{children:["Num divisions:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.numDivisions||null,format:"decimal",onChange:this.onNumDivisionsChange,checkValidity:val=>{return val>=divisionRange[0]&&val<=divisionRange[1]},placeholder:width/this.props.tickStep,useArrowKeys:true})]})," ",jsxRuntimeExports.jsxs("label",{children:["or tick step:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:this.props.tickStep||null,format:this.props.labelStyle,onChange:this.onTickStepChange,checkValidity:val=>{return val>0&&val<=width},placeholder:width/this.props.numDivisions,useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsxs("p",{children:["This controls the number (and position) of the tick marks; you can either set the number of divisions (2 divisions would split the entire range in two halves), or the tick step (the distance between ticks) and the other value will be updated accordingly."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"})," There is no check to see if labels coordinate with the tick marks, which may be confusing for users if the blue labels and black ticks are off-step."]})})]})]}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsxs("label",{children:["Snap increments per tick:"," ",jsxRuntimeExports.jsx(NumberInput$5,{value:snapDivisions,checkValidity:val=>val>0,format:this.props.labelStyle,onChange:this.onNumChange.bind(this,"snapDivisions"),useArrowKeys:true})]}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsxs("p",{children:["This determines the number of different places the point will snap between two adjacent tick marks."," ",jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx("strong",{children:"Note:"}),"Ensure the required number of snap increments is provided to answer the question."]})})]})]})}constructor(...args){super(...args),this.onRangeChange=range=>{this.props.onChange({range:range});},this.onLabelRangeChange=(i,num)=>{let labelRange=this.props.labelRange.slice();const otherNum=labelRange[1-i];if(num==null||otherNum==null){labelRange[i]=num;}else {labelRange=[Math.min(num,otherNum),Math.max(num,otherNum)];}this.props.onChange({labelRange:labelRange});},this.onDivisionRangeChange=divisionRange=>{let numDivisions=this.props.numDivisions;numDivisions=bound(numDivisions,divisionRange[0],divisionRange[1]);this.props.onChange({divisionRange:divisionRange,numDivisions:numDivisions});},this.onNumChange=(key,value)=>{const opts={};opts[key]=value;this.props.onChange(opts);},this.onNumDivisionsChange=numDivisions=>{const divRange=this.props.divisionRange.slice();numDivisions=_.isFinite(numDivisions)?Math.round(numDivisions):0;numDivisions=numDivisions<0?numDivisions*-1:numDivisions;if(numDivisions){numDivisions=Math.min(divRange[1],Math.max(divRange[0],numDivisions));this.props.onChange({tickStep:null,divisionRange:divRange,numDivisions:numDivisions});}},this.onTickStepChange=tickStep=>{this.props.onChange({numDivisions:null,tickStep:tickStep});},this.onChangeRelation=e=>{const value=e.target.value;this.props.onChange({correctRel:value,isInequality:value!=="eq"});},this.onLabelStyleChange=labelStyle=>{this.props.onChange({labelStyle:labelStyle});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}NumberLineEditor.widgetName="number-line";NumberLineEditor.defaultProps=numberLineLogic.defaultWidgetOptions;
1708
1710
 
1709
- const{InfoTip: InfoTip$7,NumberInput: NumberInput$4,TextInput: TextInput$2}=components;const{firstNumericalParse}=Util;const answerFormButtons=[{title:"Integers",value:"integer",content:"6"},{title:"Decimals",value:"decimal",content:"0.75"},{title:"Proper fractions",value:"proper",content:"⅗"},{title:"Improper fractions",value:"improper",content:"⁷⁄₄"},{title:"Mixed numbers",value:"mixed",content:"1¾"},{title:"Numbers with π",value:"pi",content:"π"}];const initAnswer=status=>{return {value:null,status:status,message:"",simplify:"required",answerForms:[],strict:false,maxError:null}};class NumericInputEditor extends React.Component{render(){const answers=this.props.answers;const commonOptionProps={size:"medium",role:"radio",style:{marginRight:"8px"}};const SettingOption=props=>{const{kind,onClick,ariaLabel,children}=props;const role=props.role??"radio";const pillProps={...commonOptionProps,"aria-label":ariaLabel,kind:kind,role:role,onClick:onClick};return jsxRuntimeExports.jsx(Pill,{...pillProps,children:children})};const RadioOption=props=>{const{answerIndex,answerProperty,value,children}=props;const isSelected=answers[answerIndex][answerProperty]===value;const kind=isSelected?"accent":"transparent";const newState={};newState[answerProperty]=value;const onClick=props.onClick??(()=>{this.updateAnswer(answerIndex,newState);});return jsxRuntimeExports.jsx(SettingOption,{kind:kind,onClick:onClick,children:children})};const unsimplifiedAnswers=i=>jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row unsimplified-options",children:[answers[i]["status"]!=="correct"&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Unsimplified answers are irrelevant for this status"})}),answers[i]["status"]==="correct"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Unsimplified answers are"}),jsxRuntimeExports.jsx("span",{className:"tooltip-for-legend",children:jsxRuntimeExports.jsxs(InfoTip$7,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "ungraded". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and after)'}),jsxRuntimeExports.jsx("p",{children:'Select "accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsxs("p",{children:['Select "wrong" ',jsxRuntimeExports.jsx("em",{children:"only"})," if we are specifically assessing the ability to simplify."]})]})}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"simplify",value:"required",children:"Ungraded"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"simplify",value:"optional",children:"Accepted"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"simplify",value:"enforced",children:"Wrong"})]})]});const suggestedAnswerTypes=i=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Possible answer formats "}),jsxRuntimeExports.jsxs(InfoTip$7,{children:[jsxRuntimeExports.jsx("p",{children:'Formats will be autoselected for you based on the given answer; to show no suggested formats and accept all types, simply have a decimal/integer be the answer. Values with π will have format "pi", and values that are fractions will have some subset (mixed will be "mixed" and "proper"; improper/proper will both be "improper" and "proper"). If you would like to specify that it is only a proper fraction (or only a mixed/improper fraction), deselect the other format. Except for specific cases, you should not need to change the autoselected formats.'}),jsxRuntimeExports.jsxs("p",{children:["To restrict the answer to ",jsxRuntimeExports.jsx("em",{children:"only"}),' an improper fraction (i.e. 7/4), select the improper fraction and toggle "strict" to true. This ',jsxRuntimeExports.jsx("b",{children:"will not"})," ","accept 1.75 as an answer."," "]}),jsxRuntimeExports.jsx("p",{children:"Unless you are testing that specific skill, please do not restrict the answer format."})]}),jsxRuntimeExports.jsx("br",{}),answerFormButtons.map(format=>{const isSelected=answers[i]["answerForms"]?.includes(format.value);const kind=isSelected?"accent":"transparent";const onClick=()=>{this.onToggleAnswerForm(i,format.value);};return jsxRuntimeExports.jsx(SettingOption,{ariaLabel:format.title,kind:kind,role:"checkbox",onClick:onClick,children:format.content},format.value)})]}),jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{children:"Answer formats are: "}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"strict",value:false,children:"Suggested"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"strict",value:true,children:"Required"})]})]});const inputSize=jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Width: "}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.size==="normal"?"accent":"transparent",onClick:()=>{this.change("size")("normal");},children:"Normal (80px)"}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.size==="small"?"accent":"transparent",onClick:()=>{this.change("size")("small");},children:"Small (40px)"}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsx("p",{children:'Use size "Normal" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them.'})})]});const rightAlign=jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Alignment: "}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.rightAlign?"transparent":"accent",onClick:()=>{this.props.onChange({rightAlign:false});},children:"Left"}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.rightAlign?"accent":"transparent",onClick:()=>{this.props.onChange({rightAlign:true});},children:"Right"})]});const labelText=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Aria label"}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsx("p",{children:"Text to describe this input. This will be shown to users using screenreaders."})})]}),jsxRuntimeExports.jsx(TextInput$2,{labelText:"aria label",value:this.props.labelText,onChange:this.change("labelText")})]});const coefficientCheck=jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Number style: "}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.coefficient?"transparent":"accent",onClick:()=>{this.props.onChange({coefficient:false});},children:"Standard"}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.coefficient?"accent":"transparent",onClick:()=>{this.props.onChange({coefficient:true});},children:"Coefficient"}),jsxRuntimeExports.jsx(InfoTip$7,{children:jsxRuntimeExports.jsx("p",{children:"A coefficient style number allows the student to use - for -1 and an empty string to mean 1."})})]});const instructions={wrong:"(address the mistake/misconception)",ungraded:"(explain in detail to avoid confusion)",correct:"(reinforce the user's understanding)"};const generateInputAnswerEditors=()=>answers.map((answer,i)=>{const editor=jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:answer.message||"",placeholder:"Why is this answer "+answer.status+"? "+instructions[answer.status],widgetEnabled:false,onChange:newProps=>{if("content"in newProps){this.updateAnswer(i,{message:newProps.content});}}});const statusProper=answer.status.charAt(0).toUpperCase()+answer.status.slice(1);const answerFormat=(answer.answerForms||[]).at(-1);const answerString=KhanMath.toNumericString(answer.value??0,answerFormat);const answerRangeText=answer.maxError?`\xb1 ${KhanMath.toNumericString(answer.maxError,answerFormat)}`:"";const answerHeading=answer.value===null?"New Answer":`${statusProper} answer: ${answerString} ${answerRangeText}`;return jsxRuntimeExports.jsx("div",{className:"perseus-widget-row answer-option",children:jsxRuntimeExports.jsxs(PerseusEditorAccordion,{animated:true,expanded:this.state.showAnswerDetails[i],onToggle:()=>{this.onToggleAnswers(i);},header:jsxRuntimeExports.jsx(LabelLarge,{children:answerHeading}),children:[jsxRuntimeExports.jsxs("div",{className:"input-answer-editor-value-container"+(answer.maxError?" with-max-error":""),children:[jsxRuntimeExports.jsxs("label",{children:["User input:",jsxRuntimeExports.jsx(NumberInput$4,{value:answer.value,className:"numeric-input-value",placeholder:"answer",format:_.last(answer.answerForms||[]),onFormatChange:(newValue,format)=>{let forms;if(format==="pi"){forms=["pi"];}else if(format==="mixed"){forms=["proper","mixed"];}else if(format==="proper"||format==="improper"){forms=["proper","improper"];}this.updateAnswer(i,{value:firstNumericalParse(newValue),answerForms:forms});},onChange:newValue=>{this.updateAnswer(i,{value:firstNumericalParse(newValue)});}})]}),jsxRuntimeExports.jsx("span",{className:"max-error-plusmn",children:"±"}),jsxRuntimeExports.jsx(NumberInput$4,{className:"max-error-input-value",placeholder:0,value:answers[i]["maxError"],format:_.last(answer.answerForms||[]),onChange:this.updateAnswer(i,"maxError")})]}),jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Status:"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"status",value:"correct",onClick:()=>{this.onEvaluationChange(i,"correct");},children:"Correct"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"status",value:"wrong",onClick:()=>{this.onEvaluationChange(i,"wrong");},children:"Wrong"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"status",value:"ungraded",onClick:()=>{this.onEvaluationChange(i,"ungraded");},children:"Ungraded"})]}),unsimplifiedAnswers(i),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:"(Articles only) Message shown to user:"}),editor,suggestedAnswerTypes(i),jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,"aria-label":`Delete ${answerHeading}`,className:"delete-item-button",onClick:()=>{this.onTrashAnswer(i);},kind:"tertiary",children:"Delete"})]})},i)});return jsxRuntimeExports.jsxs("div",{className:"perseus-input-number-editor",children:[jsxRuntimeExports.jsx(Heading,{title:"General Settings",isCollapsible:true,isOpen:this.state.showSettings,onToggle:this.onToggleHeading("Settings")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showSettings?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[inputSize,rightAlign,coefficientCheck,labelText]})}),jsxRuntimeExports.jsx(Heading,{title:"Answers",isCollapsible:true,isOpen:this.state.showAnswers,onToggle:this.onToggleHeading("Answers")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showAnswers?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[generateInputAnswerEditors(),jsxRuntimeExports.jsx(Button,{kind:"tertiary",onClick:this.addAnswer,children:"Add new answer"})]})})]})}constructor(props){super(props),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.onToggleAnswers=answerIndex=>{const showAnswerDetails=this.state.showAnswerDetails.slice();showAnswerDetails[answerIndex]=!showAnswerDetails[answerIndex];this.setState({showAnswerDetails:showAnswerDetails});},this.onToggleAnswerForm=(answerIndex,answerForm)=>{let answerForms=[...this.props.answers[answerIndex]["answerForms"]??[]];const formSelected=answerForms.includes(answerForm);if(!formSelected){answerForms.push(answerForm);}else {answerForms=answerForms.filter(form=>form!==answerForm);}const updateFn=this.updateAnswer(answerIndex,"answerForms");if(updateFn){updateFn(answerForms);}},this.onToggleHeading=accordionName=>{return ()=>{const toggleName=`show${accordionName}`;const newState={...this.state};newState[toggleName]=!newState[toggleName];this.setState(newState);}},this.onTrashAnswer=choiceIndex=>{if(choiceIndex>=0&&choiceIndex<this.props.answers.length){const answers=this.props.answers.slice(0);answers.splice(choiceIndex,1);this.props.onChange({answers:answers});}},this.onSpace=(e,callback,...args)=>{if(e.key===" "){e.preventDefault();callback.apply(this,args);}},this.onStatusChange=choiceIndex=>{const statuses=["wrong","ungraded","correct"];const answers=this.props.answers;const i=statuses.indexOf(answers[choiceIndex].status);const newStatus=statuses[(i+1)%statuses.length];this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.onEvaluationChange=(choiceIndex,newStatus)=>{this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.updateAnswer=(choiceIndex,update)=>{if(!_.isObject(update)){return _.partial((choiceIndex,key,value)=>{const update={};update[key]=value;this.updateAnswer(choiceIndex,update);},choiceIndex,update)}let answers=[...this.props.answers];if(choiceIndex===answers.length){const lastAnswer=initAnswer(this.state.lastStatus);answers=answers.concat(lastAnswer);}answers[choiceIndex]=_.extend({},answers[choiceIndex],update);this.props.onChange({answers:answers});},this.addAnswer=()=>{const lastAnswer=initAnswer(this.state.lastStatus);const answers=this.props.answers.concat(lastAnswer);const showAnswerDetails=this.state.showAnswerDetails.concat(true);this.setState({showAnswerDetails:showAnswerDetails});this.props.onChange({answers:answers});},this.getSaveWarnings=()=>{const warnings=[];if(_.contains(_.pluck(this.props.answers,"value"),"")){warnings.push("One or more answers is empty");}this.props.answers.forEach((answer,i)=>{const formatError=answer.strict&&(!answer.answerForms||answer.answerForms.length===0);if(formatError){warnings.push(`Answer ${i+1} is set to string format `+"matching, but no format was selected");}});return warnings},this.serialize=()=>{return EditorJsonify.serialize.call(this)};this.state={lastStatus:"wrong",showAnswerDetails:Array(this.props.answers.length).fill(true),showSettings:true,showAnswers:true};}}NumericInputEditor.widgetName="numeric-input";NumericInputEditor.displayName="NumericInputEditor";NumericInputEditor.defaultProps=numericInputLogic.defaultWidgetOptions;
1711
+ const{InfoTip: InfoTip$6,NumberInput: NumberInput$4,TextInput: TextInput$2}=components;const{firstNumericalParse}=Util;const answerFormButtons=[{title:"Integers",value:"integer",content:"6"},{title:"Decimals",value:"decimal",content:"0.75"},{title:"Proper fractions",value:"proper",content:"⅗"},{title:"Improper fractions",value:"improper",content:"⁷⁄₄"},{title:"Mixed numbers",value:"mixed",content:"1¾"},{title:"Numbers with π",value:"pi",content:"π"}];const initAnswer=status=>{return {value:null,status:status,message:"",simplify:"required",answerForms:[],strict:false,maxError:null}};class NumericInputEditor extends React.Component{render(){const answers=this.props.answers;const commonOptionProps={size:"medium",role:"radio",style:{marginRight:"8px"}};const SettingOption=props=>{const{kind,onClick,ariaLabel,children}=props;const role=props.role??"radio";const pillProps={...commonOptionProps,"aria-label":ariaLabel,kind:kind,role:role,onClick:onClick};return jsxRuntimeExports.jsx(Pill,{...pillProps,children:children})};const RadioOption=props=>{const{answerIndex,answerProperty,value,children}=props;const isSelected=answers[answerIndex][answerProperty]===value;const kind=isSelected?"accent":"transparent";const newState={};newState[answerProperty]=value;const onClick=props.onClick??(()=>{this.updateAnswer(answerIndex,newState);});return jsxRuntimeExports.jsx(SettingOption,{kind:kind,onClick:onClick,children:children})};const unsimplifiedAnswers=i=>jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row unsimplified-options",children:[answers[i]["status"]!=="correct"&&jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment,{children:jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Unsimplified answers are irrelevant for this status"})}),answers[i]["status"]==="correct"&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Unsimplified answers are"}),jsxRuntimeExports.jsx("span",{className:"tooltip-for-legend",children:jsxRuntimeExports.jsxs(InfoTip$6,{children:[jsxRuntimeExports.jsx("p",{children:'Normally select "ungraded". This will give the user a message saying the answer is correct but not simplified. The user will then have to simplify it and re-enter, but will not be penalized. (5th grade and after)'}),jsxRuntimeExports.jsx("p",{children:'Select "accepted" only if the user is not expected to know how to simplify fractions yet. (Anything prior to 5th grade)'}),jsxRuntimeExports.jsxs("p",{children:['Select "wrong" ',jsxRuntimeExports.jsx("em",{children:"only"})," if we are specifically assessing the ability to simplify."]})]})}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"simplify",value:"required",children:"Ungraded"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"simplify",value:"optional",children:"Accepted"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"simplify",value:"enforced",children:"Wrong"})]})]});const suggestedAnswerTypes=i=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Possible answer formats "}),jsxRuntimeExports.jsxs(InfoTip$6,{children:[jsxRuntimeExports.jsx("p",{children:'Formats will be autoselected for you based on the given answer; to show no suggested formats and accept all types, simply have a decimal/integer be the answer. Values with π will have format "pi", and values that are fractions will have some subset (mixed will be "mixed" and "proper"; improper/proper will both be "improper" and "proper"). If you would like to specify that it is only a proper fraction (or only a mixed/improper fraction), deselect the other format. Except for specific cases, you should not need to change the autoselected formats.'}),jsxRuntimeExports.jsxs("p",{children:["To restrict the answer to ",jsxRuntimeExports.jsx("em",{children:"only"}),' an improper fraction (i.e. 7/4), select the improper fraction and toggle "strict" to true. This ',jsxRuntimeExports.jsx("b",{children:"will not"})," ","accept 1.75 as an answer."," "]}),jsxRuntimeExports.jsx("p",{children:"Unless you are testing that specific skill, please do not restrict the answer format."})]}),jsxRuntimeExports.jsx("br",{}),answerFormButtons.map(format=>{const isSelected=answers[i]["answerForms"]?.includes(format.value);const kind=isSelected?"accent":"transparent";const onClick=()=>{this.onToggleAnswerForm(i,format.value);};return jsxRuntimeExports.jsx(SettingOption,{ariaLabel:format.title,kind:kind,role:"checkbox",onClick:onClick,children:format.content},format.value)})]}),jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{children:"Answer formats are: "}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"strict",value:false,children:"Suggested"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"strict",value:true,children:"Required"})]})]});const inputSize=jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Width: "}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.size==="normal"?"accent":"transparent",onClick:()=>{this.change("size")("normal");},children:"Normal (80px)"}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.size==="small"?"accent":"transparent",onClick:()=>{this.change("size")("small");},children:"Small (40px)"}),jsxRuntimeExports.jsx(InfoTip$6,{children:jsxRuntimeExports.jsx("p",{children:'Use size "Normal" for all text boxes, unless there are multiple text boxes in one line and the answer area is too narrow to fit them.'})})]});const rightAlign=jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Alignment: "}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.rightAlign?"transparent":"accent",onClick:()=>{this.props.onChange({rightAlign:false});},children:"Left"}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.rightAlign?"accent":"transparent",onClick:()=>{this.props.onChange({rightAlign:true});},children:"Right"})]});const labelText=jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("label",{children:"Aria label"}),jsxRuntimeExports.jsx(InfoTip$6,{children:jsxRuntimeExports.jsx("p",{children:"Text to describe this input. This will be shown to users using screenreaders."})})]}),jsxRuntimeExports.jsx(TextInput$2,{labelText:"aria label",value:this.props.labelText,onChange:this.change("labelText")})]});const coefficientCheck=jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Number style: "}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.coefficient?"transparent":"accent",onClick:()=>{this.props.onChange({coefficient:false});},children:"Standard"}),jsxRuntimeExports.jsx(Pill,{...commonOptionProps,kind:this.props.coefficient?"accent":"transparent",onClick:()=>{this.props.onChange({coefficient:true});},children:"Coefficient"}),jsxRuntimeExports.jsx(InfoTip$6,{children:jsxRuntimeExports.jsx("p",{children:"A coefficient style number allows the student to use - for -1 and an empty string to mean 1."})})]});const instructions={wrong:"(address the mistake/misconception)",ungraded:"(explain in detail to avoid confusion)",correct:"(reinforce the user's understanding)"};const generateInputAnswerEditors=()=>answers.map((answer,i)=>{const editor=jsxRuntimeExports.jsx(Editor,{apiOptions:this.props.apiOptions,content:answer.message||"",placeholder:"Why is this answer "+answer.status+"? "+instructions[answer.status],widgetEnabled:false,onChange:newProps=>{if("content"in newProps){this.updateAnswer(i,{message:newProps.content});}}});const statusProper=answer.status.charAt(0).toUpperCase()+answer.status.slice(1);const answerFormat=(answer.answerForms||[]).at(-1);const answerString=KhanMath.toNumericString(answer.value??0,answerFormat);const answerRangeText=answer.maxError?`\xb1 ${KhanMath.toNumericString(answer.maxError,answerFormat)}`:"";const answerHeading=answer.value===null?"New Answer":`${statusProper} answer: ${answerString} ${answerRangeText}`;return jsxRuntimeExports.jsx("div",{className:"perseus-widget-row answer-option",children:jsxRuntimeExports.jsxs(PerseusEditorAccordion,{animated:true,expanded:this.state.showAnswerDetails[i],onToggle:()=>{this.onToggleAnswers(i);},header:jsxRuntimeExports.jsx(LabelLarge,{children:answerHeading}),children:[jsxRuntimeExports.jsxs("div",{className:"input-answer-editor-value-container"+(answer.maxError?" with-max-error":""),children:[jsxRuntimeExports.jsxs("label",{children:["User input:",jsxRuntimeExports.jsx(NumberInput$4,{value:answer.value,className:"numeric-input-value",placeholder:"answer",format:_.last(answer.answerForms||[]),onFormatChange:(newValue,format)=>{let forms;if(format==="pi"){forms=["pi"];}else if(format==="mixed"){forms=["proper","mixed"];}else if(format==="proper"||format==="improper"){forms=["proper","improper"];}this.updateAnswer(i,{value:firstNumericalParse(newValue),answerForms:forms});},onChange:newValue=>{this.updateAnswer(i,{value:firstNumericalParse(newValue)});}})]}),jsxRuntimeExports.jsx("span",{className:"max-error-plusmn",children:"±"}),jsxRuntimeExports.jsx(NumberInput$4,{className:"max-error-input-value",placeholder:0,value:answers[i]["maxError"],format:_.last(answer.answerForms||[]),onChange:this.updateAnswer(i,"maxError")})]}),jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx("legend",{className:"inline-options",children:"Status:"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"status",value:"correct",onClick:()=>{this.onEvaluationChange(i,"correct");},children:"Correct"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"status",value:"wrong",onClick:()=>{this.onEvaluationChange(i,"wrong");},children:"Wrong"}),jsxRuntimeExports.jsx(RadioOption,{answerIndex:i,answerProperty:"status",value:"ungraded",onClick:()=>{this.onEvaluationChange(i,"ungraded");},children:"Ungraded"})]}),unsimplifiedAnswers(i),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:"(Articles only) Message shown to user:"}),editor,suggestedAnswerTypes(i),jsxRuntimeExports.jsx(Button,{startIcon:trashIcon,"aria-label":`Delete ${answerHeading}`,className:"delete-item-button",onClick:()=>{this.onTrashAnswer(i);},kind:"tertiary",children:"Delete"})]})},i)});return jsxRuntimeExports.jsxs("div",{className:"perseus-input-number-editor",children:[jsxRuntimeExports.jsx(Heading,{title:"General Settings",isCollapsible:true,isOpen:this.state.showSettings,onToggle:this.onToggleHeading("Settings")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showSettings?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[inputSize,rightAlign,coefficientCheck,labelText]})}),jsxRuntimeExports.jsx(Heading,{title:"Answers",isCollapsible:true,isOpen:this.state.showAnswers,onToggle:this.onToggleHeading("Answers")}),jsxRuntimeExports.jsx("div",{className:`perseus-editor-accordion-container ${this.state.showAnswers?"expanded":"collapsed"}`,children:jsxRuntimeExports.jsxs("div",{className:"perseus-editor-accordion-content",children:[generateInputAnswerEditors(),jsxRuntimeExports.jsx(Button,{kind:"tertiary",onClick:this.addAnswer,children:"Add new answer"})]})})]})}constructor(props){super(props),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.onToggleAnswers=answerIndex=>{const showAnswerDetails=this.state.showAnswerDetails.slice();showAnswerDetails[answerIndex]=!showAnswerDetails[answerIndex];this.setState({showAnswerDetails:showAnswerDetails});},this.onToggleAnswerForm=(answerIndex,answerForm)=>{let answerForms=[...this.props.answers[answerIndex]["answerForms"]??[]];const formSelected=answerForms.includes(answerForm);if(!formSelected){answerForms.push(answerForm);}else {answerForms=answerForms.filter(form=>form!==answerForm);}const updateFn=this.updateAnswer(answerIndex,"answerForms");if(updateFn){updateFn(answerForms);}},this.onToggleHeading=accordionName=>{return ()=>{const toggleName=`show${accordionName}`;const newState={...this.state};newState[toggleName]=!newState[toggleName];this.setState(newState);}},this.onTrashAnswer=choiceIndex=>{if(choiceIndex>=0&&choiceIndex<this.props.answers.length){const answers=this.props.answers.slice(0);answers.splice(choiceIndex,1);this.props.onChange({answers:answers});}},this.onSpace=(e,callback,...args)=>{if(e.key===" "){e.preventDefault();callback.apply(this,args);}},this.onStatusChange=choiceIndex=>{const statuses=["wrong","ungraded","correct"];const answers=this.props.answers;const i=statuses.indexOf(answers[choiceIndex].status);const newStatus=statuses[(i+1)%statuses.length];this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.onEvaluationChange=(choiceIndex,newStatus)=>{this.updateAnswer(choiceIndex,{status:newStatus,simplify:newStatus==="correct"?"required":"accepted"});},this.updateAnswer=(choiceIndex,update)=>{if(!_.isObject(update)){return _.partial((choiceIndex,key,value)=>{const update={};update[key]=value;this.updateAnswer(choiceIndex,update);},choiceIndex,update)}let answers=[...this.props.answers];if(choiceIndex===answers.length){const lastAnswer=initAnswer(this.state.lastStatus);answers=answers.concat(lastAnswer);}answers[choiceIndex]=_.extend({},answers[choiceIndex],update);this.props.onChange({answers:answers});},this.addAnswer=()=>{const lastAnswer=initAnswer(this.state.lastStatus);const answers=this.props.answers.concat(lastAnswer);const showAnswerDetails=this.state.showAnswerDetails.concat(true);this.setState({showAnswerDetails:showAnswerDetails});this.props.onChange({answers:answers});},this.getSaveWarnings=()=>{const warnings=[];if(_.contains(_.pluck(this.props.answers,"value"),"")){warnings.push("One or more answers is empty");}this.props.answers.forEach((answer,i)=>{const formatError=answer.strict&&(!answer.answerForms||answer.answerForms.length===0);if(formatError){warnings.push(`Answer ${i+1} is set to string format `+"matching, but no format was selected");}});return warnings},this.serialize=()=>{return EditorJsonify.serialize.call(this)};this.state={lastStatus:"wrong",showAnswerDetails:Array(this.props.answers.length).fill(true),showSettings:true,showAnswers:true};}}NumericInputEditor.widgetName="numeric-input";NumericInputEditor.displayName="NumericInputEditor";NumericInputEditor.defaultProps=numericInputLogic.defaultWidgetOptions;
1710
1712
 
1711
- const{InfoTip: InfoTip$6,TextListEditor: TextListEditor$2}=components;const NORMAL="normal";const AUTO="auto";const HORIZONTAL$1="horizontal";const VERTICAL$1="vertical";const getUpdatedOptions=(correctOptions,otherOptions,whichOptions,options)=>{const props={};if(whichOptions&&options!==undefined){props[whichOptions]=options.map(option=>({content:option}));}const correctOptionsToUse=whichOptions==="correctOptions"?props.correctOptions:correctOptions;const otherOptionsToUse=whichOptions==="otherOptions"?props.otherOptions:otherOptions;const allOptions=[...correctOptionsToUse,...otherOptionsToUse];const updatedOptions=[...new Set(allOptions.map(item=>item.content))].filter(content=>content!=="").sort().sort((a,b)=>{const getCategoryScore=content=>{if(/\d/.test(content)){return 0}if(/^\$?[a-zA-Z]+\$?$/.test(content)){return 2}return 1};return getCategoryScore(a)-getCategoryScore(b)}).map(content=>({content}));return {...props,options:updatedOptions}};class OrdererEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-orderer",children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$6,{children:jsxRuntimeExports.jsx("p",{children:"Place the cards in the correct order. The same card can be used more than once in the answer but will only be displayed once at the top of a stack of identical cards."})})]}),jsxRuntimeExports.jsx(TextListEditor$2,{options:_.pluck(this.props.correctOptions,"content"),onChange:this.onOptionsChange.bind(this,"correctOptions"),layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[" ","Other cards:"," ",jsxRuntimeExports.jsx(InfoTip$6,{children:jsxRuntimeExports.jsx("p",{children:"Create cards that are not part of the answer."})})]}),jsxRuntimeExports.jsx(TextListEditor$2,{options:_.pluck(this.props.otherOptions,"content"),onChange:this.onOptionsChange.bind(this,"otherOptions"),layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Layout:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.layout,onChange:this.onLayoutChange,children:[jsxRuntimeExports.jsx("option",{value:HORIZONTAL$1,children:"Horizontal"}),jsxRuntimeExports.jsx("option",{value:VERTICAL$1,children:"Vertical"})]})]}),jsxRuntimeExports.jsx(InfoTip$6,{children:jsxRuntimeExports.jsx("p",{children:"Use the horizontal layout for short text and small images. The vertical layout is best for longer text (e.g. proofs)."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Height:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.height,onChange:this.onHeightChange,children:[jsxRuntimeExports.jsx("option",{value:NORMAL,children:"Normal"}),jsxRuntimeExports.jsx("option",{value:AUTO,children:"Automatic"})]})]}),jsxRuntimeExports.jsx(InfoTip$6,{children:jsxRuntimeExports.jsx("p",{children:'Use "Normal" for text, "Automatic" for images.'})})]})]})}constructor(...args){super(...args),this.onOptionsChange=(whichOptions,options,cb)=>{const updatedOptions=getUpdatedOptions(this.props.correctOptions||[],this.props.otherOptions||[],whichOptions,options);this.props.onChange(updatedOptions,cb);},this.onLayoutChange=e=>{this.props.onChange({layout:e.target.value});},this.onHeightChange=e=>{this.props.onChange({height:e.target.value});},this.serialize=()=>{const{options}=getUpdatedOptions(this.props.correctOptions||[],this.props.otherOptions||[]);return {options:options,correctOptions:this.props.correctOptions,otherOptions:this.props.otherOptions,height:this.props.height,layout:this.props.layout}};}}OrdererEditor.propTypes={correctOptions:PropTypes.array,otherOptions:PropTypes.array,height:PropTypes.oneOf([NORMAL,AUTO]),layout:PropTypes.oneOf([HORIZONTAL$1,VERTICAL$1]),onChange:PropTypes.func.isRequired};OrdererEditor.widgetName="orderer";OrdererEditor.defaultProps=ordererLogic.defaultWidgetOptions;
1713
+ const{InfoTip: InfoTip$5,TextListEditor: TextListEditor$2}=components;const NORMAL="normal";const AUTO="auto";const HORIZONTAL$1="horizontal";const VERTICAL$1="vertical";const getUpdatedOptions=(correctOptions,otherOptions,whichOptions,options)=>{const props={};if(whichOptions&&options!==undefined){props[whichOptions]=options.map(option=>({content:option}));}const correctOptionsToUse=whichOptions==="correctOptions"?props.correctOptions:correctOptions;const otherOptionsToUse=whichOptions==="otherOptions"?props.otherOptions:otherOptions;const allOptions=[...correctOptionsToUse,...otherOptionsToUse];const updatedOptions=[...new Set(allOptions.map(item=>item.content))].filter(content=>content!=="").sort().sort((a,b)=>{const getCategoryScore=content=>{if(/\d/.test(content)){return 0}if(/^\$?[a-zA-Z]+\$?$/.test(content)){return 2}return 1};return getCategoryScore(a)-getCategoryScore(b)}).map(content=>({content}));return {...props,options:updatedOptions}};class OrdererEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-orderer",children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$5,{children:jsxRuntimeExports.jsx("p",{children:"Place the cards in the correct order. The same card can be used more than once in the answer but will only be displayed once at the top of a stack of identical cards."})})]}),jsxRuntimeExports.jsx(TextListEditor$2,{options:_.pluck(this.props.correctOptions,"content"),onChange:this.onOptionsChange.bind(this,"correctOptions"),layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[" ","Other cards:"," ",jsxRuntimeExports.jsx(InfoTip$5,{children:jsxRuntimeExports.jsx("p",{children:"Create cards that are not part of the answer."})})]}),jsxRuntimeExports.jsx(TextListEditor$2,{options:_.pluck(this.props.otherOptions,"content"),onChange:this.onOptionsChange.bind(this,"otherOptions"),layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Layout:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.layout,onChange:this.onLayoutChange,children:[jsxRuntimeExports.jsx("option",{value:HORIZONTAL$1,children:"Horizontal"}),jsxRuntimeExports.jsx("option",{value:VERTICAL$1,children:"Vertical"})]})]}),jsxRuntimeExports.jsx(InfoTip$5,{children:jsxRuntimeExports.jsx("p",{children:"Use the horizontal layout for short text and small images. The vertical layout is best for longer text (e.g. proofs)."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Height:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.height,onChange:this.onHeightChange,children:[jsxRuntimeExports.jsx("option",{value:NORMAL,children:"Normal"}),jsxRuntimeExports.jsx("option",{value:AUTO,children:"Automatic"})]})]}),jsxRuntimeExports.jsx(InfoTip$5,{children:jsxRuntimeExports.jsx("p",{children:'Use "Normal" for text, "Automatic" for images.'})})]})]})}constructor(...args){super(...args),this.onOptionsChange=(whichOptions,options,cb)=>{const updatedOptions=getUpdatedOptions(this.props.correctOptions||[],this.props.otherOptions||[],whichOptions,options);this.props.onChange(updatedOptions,cb);},this.onLayoutChange=e=>{this.props.onChange({layout:e.target.value});},this.onHeightChange=e=>{this.props.onChange({height:e.target.value});},this.serialize=()=>{const{options}=getUpdatedOptions(this.props.correctOptions||[],this.props.otherOptions||[]);return {options:options,correctOptions:this.props.correctOptions,otherOptions:this.props.otherOptions,height:this.props.height,layout:this.props.layout}};}}OrdererEditor.propTypes={correctOptions:PropTypes.array,otherOptions:PropTypes.array,height:PropTypes.oneOf([NORMAL,AUTO]),layout:PropTypes.oneOf([HORIZONTAL$1,VERTICAL$1]),onChange:PropTypes.func.isRequired};OrdererEditor.widgetName="orderer";OrdererEditor.defaultProps=ordererLogic.defaultWidgetOptions;
1712
1714
 
1713
- const{InfoTip: InfoTip$5}=components;class PassageEditor extends React.Component{render(){const passageEditor=jsxRuntimeExports.jsx(Editor,{ref:"passage-editor",apiOptions:this.props.apiOptions,content:this.props.passageText,widgetEnabled:false,placeholder:"Type passage here...",onChange:newProps=>{this.change({passageText:newProps.content});},showWordCount:true});const footnotesEditor=jsxRuntimeExports.jsx(Editor,{ref:"passage-footnotes-editor",apiOptions:this.props.apiOptions,content:this.props.footnotes,widgetEnabled:false,placeholder:"Type footnotes here...",onChange:newProps=>{this.change({footnotes:newProps.content});}});return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-passage-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show line numbers",checked:this.props.showLineNumbers,onChange:value=>{this.props.onChange({showLineNumbers:value});}})}),jsxRuntimeExports.jsxs("div",{children:["Passage title:",jsxRuntimeExports.jsx(InfoTip$5,{children:jsxRuntimeExports.jsx("p",{children:"An optional title that will appear directly above the passage in the same font style. (E.g. Passage 1)"})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.passageTitle,onChange:e=>{this.change({passageTitle:e.target.value});}})})]}),jsxRuntimeExports.jsxs("div",{children:["Passage Text:",passageEditor]}),jsxRuntimeExports.jsxs("div",{children:["Footnotes:",jsxRuntimeExports.jsx(InfoTip$5,{children:jsxRuntimeExports.jsx("p",{children:"To add footnotes, add ^ characters where they belong in the passage. Then, add ^ in the footnotes area to reference the footnotes in the passage."})}),footnotesEditor]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PassageEditor.propTypes={...Changeable.propTypes,passageTitle:PropTypes.string,passageText:PropTypes.string,footnotes:PropTypes.string,showLineNumbers:PropTypes.bool};PassageEditor.widgetName="passage";PassageEditor.defaultProps=passageLogic.defaultWidgetOptions;
1715
+ const{InfoTip: InfoTip$4}=components;class PassageEditor extends React.Component{render(){const passageEditor=jsxRuntimeExports.jsx(Editor,{ref:"passage-editor",apiOptions:this.props.apiOptions,content:this.props.passageText,widgetEnabled:false,placeholder:"Type passage here...",onChange:newProps=>{this.change({passageText:newProps.content});},showWordCount:true});const footnotesEditor=jsxRuntimeExports.jsx(Editor,{ref:"passage-footnotes-editor",apiOptions:this.props.apiOptions,content:this.props.footnotes,widgetEnabled:false,placeholder:"Type footnotes here...",onChange:newProps=>{this.change({footnotes:newProps.content});}});return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-passage-editor",children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsx(Checkbox$1,{label:"Show line numbers",checked:this.props.showLineNumbers,onChange:value=>{this.props.onChange({showLineNumbers:value});}})}),jsxRuntimeExports.jsxs("div",{children:["Passage title:",jsxRuntimeExports.jsx(InfoTip$4,{children:jsxRuntimeExports.jsx("p",{children:"An optional title that will appear directly above the passage in the same font style. (E.g. Passage 1)"})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx("input",{type:"text",defaultValue:this.props.passageTitle,onChange:e=>{this.change({passageTitle:e.target.value});}})})]}),jsxRuntimeExports.jsxs("div",{children:["Passage Text:",passageEditor]}),jsxRuntimeExports.jsxs("div",{children:["Footnotes:",jsxRuntimeExports.jsx(InfoTip$4,{children:jsxRuntimeExports.jsx("p",{children:"To add footnotes, add ^ characters where they belong in the passage. Then, add ^ in the footnotes area to reference the footnotes in the passage."})}),footnotesEditor]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PassageEditor.propTypes={...Changeable.propTypes,passageTitle:PropTypes.string,passageText:PropTypes.string,footnotes:PropTypes.string,showLineNumbers:PropTypes.bool};PassageEditor.widgetName="passage";PassageEditor.defaultProps=passageLogic.defaultWidgetOptions;
1714
1716
 
1715
- const{InfoTip: InfoTip$4,NumberInput: NumberInput$3,TextInput: TextInput$1}=components;class PassageRefEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Passage Number: ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.passageNumber,onChange:this.change("passageNumber")})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Reference Number: ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.referenceNumber,onChange:this.change("referenceNumber")})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Summary Text: ",jsxRuntimeExports.jsx(TextInput$1,{value:this.props.summaryText,onChange:this.change("summaryText")}),jsxRuntimeExports.jsxs(InfoTip$4,{children:[jsxRuntimeExports.jsx("p",{children:"Short summary of the referenced section. This will be included in parentheses and quotes automatically."}),jsxRuntimeExports.jsx("p",{children:"Ex: The start ... the end"})]})]})})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PassageRefEditor.propTypes={...Changeable.propTypes,passageNumber:PropTypes.number,referenceNumber:PropTypes.number,summaryText:PropTypes.string};PassageRefEditor.widgetName="passage-ref";PassageRefEditor.defaultProps=passageRefLogic.defaultWidgetOptions;
1717
+ const{InfoTip: InfoTip$3,NumberInput: NumberInput$3,TextInput: TextInput$1}=components;class PassageRefEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Passage Number: ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.passageNumber,onChange:this.change("passageNumber")})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Reference Number: ",jsxRuntimeExports.jsx(NumberInput$3,{value:this.props.referenceNumber,onChange:this.change("referenceNumber")})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Summary Text: ",jsxRuntimeExports.jsx(TextInput$1,{value:this.props.summaryText,onChange:this.change("summaryText")}),jsxRuntimeExports.jsxs(InfoTip$3,{children:[jsxRuntimeExports.jsx("p",{children:"Short summary of the referenced section. This will be included in parentheses and quotes automatically."}),jsxRuntimeExports.jsx("p",{children:"Ex: The start ... the end"})]})]})})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PassageRefEditor.propTypes={...Changeable.propTypes,passageNumber:PropTypes.number,referenceNumber:PropTypes.number,summaryText:PropTypes.string};PassageRefEditor.widgetName="passage-ref";PassageRefEditor.defaultProps=passageRefLogic.defaultWidgetOptions;
1716
1718
 
1717
1719
  class PassageRefTargetEditor extends React.Component{render(){return jsxRuntimeExports.jsxs("div",{children:["Content:",jsxRuntimeExports.jsx("input",{type:"text",value:this.props.content,onChange:this.handleContentChange})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.handleContentChange=e=>{this.change({content:e.target.value});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}PassageRefTargetEditor.propTypes={...Changeable.propTypes,content:PropTypes.string};PassageRefTargetEditor.widgetName="passage-ref-target";PassageRefTargetEditor.defaultProps=passageRefTargetLogic.defaultWidgetOptions;
1718
1720
 
1719
1721
  class PhetSimulationEditor extends React.Component{serialize(){return {url:this.props.url,description:this.props.description}}render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(LabeledTextField,{label:"URL",value:this.props.url,onChange:url=>this.props.onChange({url}),style:{marginBottom:spacing.large_24}}),jsxRuntimeExports.jsx(LabeledTextField,{label:"Description",value:this.props.description,onChange:description=>this.props.onChange({description})})]})}constructor(...args){super(...args),this.getSaveWarnings=()=>{if(makeSafeUrl(this.props.url,"en","https://phet.colorado.edu")===null){return ["Please enter a URL from the PhET domain."]}return []};}}PhetSimulationEditor.defaultProps=phetSimulationLogic.defaultWidgetOptions;PhetSimulationEditor.widgetName="phet-simulation";
1720
1722
 
1721
- const{InfoTip: InfoTip$3,NumberInput: NumberInput$2,RangeInput,TextListEditor: TextListEditor$1}=components;const Plotter=PlotterWidget.widget;const STARTING="starting";const CORRECT="correct";const editingStates=[STARTING,CORRECT];function padArray(array,n,value){const copy=_.clone(array);copy.length=n;for(let i=array.length;i<n;i++){copy[i]=value;}return copy}const editorDefaults={scaleY:1,maxY:10,snapsPerLine:2};const formatNumber=num=>"$"+number.round(num,2)+"$";class PlotterEditor extends React.Component{UNSAFE_componentWillMount(){this.fetchPic(this.props.picUrl);}UNSAFE_componentWillReceiveProps(nextProps){this.fetchPic(nextProps.picUrl);if(nextProps.static){this.setState({editing:"starting"});}}render(){const setFromScale=_.contains(["line","histogram","dotplot"],this.props.type);const canChangeSnaps=!_.contains(["pic","dotplot"],this.props.type);const plotterProps={...this.props,trackInteraction:()=>{},starting:this.props[this.state.editing],onChange:this.handlePlotterChange,userInput:this.props.correct,handleUserInput:userInput=>{this.props.onChange({correct:userInput});}};return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-plotter-editor",children:[jsxRuntimeExports.jsxs("div",{children:["Chart type:"," ",plotterPlotTypes.map(type=>{return jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",name:"chart-type",checked:this.props.type===type,onChange:_.partial(this.changeType,type)}),type]},type)},this)]}),jsxRuntimeExports.jsxs("div",{children:["Labels:"," ",["x","y"].map((axis,i)=>{return jsxRuntimeExports.jsxs("label",{children:[axis+":",jsxRuntimeExports.jsx("input",{type:"text",onChange:_.partial(this.changeLabel,i),defaultValue:this.props.labels[i]})]},axis)},this)]}),setFromScale&&jsxRuntimeExports.jsxs("div",{className:"set-from-scale-box",children:[jsxRuntimeExports.jsx("span",{className:"categories-title",children:"Set Categories From Scale"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Tick Step:"," ",jsxRuntimeExports.jsx(NumberInput$2,{placeholder:1,useArrowKeys:true,value:this.state.tickStep,onChange:this.handleChangeTickStep})]}),jsxRuntimeExports.jsx(InfoTip$3,{children:jsxRuntimeExports.jsx("p",{children:"The difference between adjacent ticks."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Range:"," ",jsxRuntimeExports.jsx(RangeInput,{placeholder:[0,10],useArrowKeys:true,value:[this.state.minX,this.state.maxX],onChange:this.handleChangeRange})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("button",{onClick:this.setCategoriesFromScale,children:["Set Categories"," "]})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Label Interval:"," ",jsxRuntimeExports.jsx(NumberInput$2,{useArrowKeys:true,value:this.props.labelInterval,onChange:this.changeLabelInterval})]}),jsxRuntimeExports.jsx(InfoTip$3,{children:jsxRuntimeExports.jsx("p",{children:'Which ticks to display the labels for. For instance, setting this to "4" will only show every 4th label (plus the last one)'})})]}),this.props.type==="pic"&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Picture:"," ",jsxRuntimeExports.jsx(BlurInput,{className:"pic-url",value:this.props.picUrl,onChange:this.changePicUrl}),jsxRuntimeExports.jsx(InfoTip$3,{children:jsxRuntimeExports.jsx("p",{children:'Use the default picture of Earth, or insert the URL for a different picture using the "Add image" function.'})})]}),this.state.pic&&this.state.pic.width!==this.state.pic.height&&jsxRuntimeExports.jsxs("p",{className:"warning",children:[jsxRuntimeExports.jsx("b",{children:"Warning"}),": You are using a picture which is not square. This means the image will get distorted. You should probably crop it to be square."]})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Categories:"," ",jsxRuntimeExports.jsx(TextListEditor$1,{ref:"categories",layout:"horizontal",options:this.props.categories,onChange:this.changeCategories})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Scale (y):"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeScale,defaultValue:this.props.scaleY})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Max y:"," ",jsxRuntimeExports.jsx("input",{type:"text",ref:"maxY",onChange:this.changeMax,defaultValue:this.props.maxY})]})}),canChangeSnaps&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Snaps per line:"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeSnaps,defaultValue:this.props.snapsPerLine})]}),jsxRuntimeExports.jsx(InfoTip$3,{children:jsxRuntimeExports.jsx("p",{children:"Creates the specified number of divisions between the horizontal lines. Fewer snaps between lines makes the graph easier for the student to create correctly."})})]}),jsxRuntimeExports.jsxs("div",{children:["Editing values:"," ",editingStates.map(editing=>jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",disabled:editing===CORRECT&&this.props.static,checked:this.props.static?editing===STARTING:this.state.editing===editing,onChange:e=>this.changeEditing(editing)}),editing]},editing)),jsxRuntimeExports.jsxs(InfoTip$3,{children:[jsxRuntimeExports.jsx("p",{children:"Use this toggle to switch between editing the correct answer (what the student will be graded on) and the starting values (what the student will see plotted when they start the problem). Note: These cannot be the same."}),jsxRuntimeExports.jsx("p",{children:"In static mode, the starting values are rendered out to the displayed widget."})]})]}),jsxRuntimeExports.jsx(Plotter,{...plotterProps})]})}constructor(...args){super(...args),this.state={editing:this.props.static?STARTING:CORRECT,pic:null,loadedUrl:null,minX:null,maxX:null,tickStep:null},this.fetchPic=url=>{if(this.state.loadedUrl!==url){const pic=new Image;pic.src=url;pic.onload=()=>{this.setState({pic:pic,loadedUrl:url});};}},this.handleChangeTickStep=value=>{this.setState({tickStep:value});},this.handleChangeRange=newValue=>{this.setState({minX:newValue[0],maxX:newValue[1]});},this.changeLabelInterval=value=>{this.props.onChange({labelInterval:value});},this.handlePlotterChange=newProps=>{const props={};props[this.state.editing]=newProps.values;this.props.onChange(props);},this.changeType=type=>{let categories;if(type==="histogram"){categories=[formatNumber(0)].concat(this.props.categories);this.props.onChange({type:type,categories:categories});}else if(this.props.type==="histogram"){categories=this.props.categories.slice(1);this.props.onChange({type:type,categories:categories});}else {this.props.onChange({type:type});}if(categories){const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");}},this.changeLabel=(i,e)=>{const labels=_.clone(this.props.labels);labels[i]=e.target.value;this.props.onChange({labels:labels});},this.changePicUrl=value=>{const url=Util.getRealImageUrl(value);this.props.onChange({picUrl:url});},this.changeCategories=categories=>{let n=categories.length;if(this.props.type==="histogram"){n--;}const value=this.props.scaleY;this.props.onChange({categories:categories,correct:padArray(this.props.correct,n,value),starting:padArray(this.props.starting,n,value)});},this.changeScale=e=>{const oldScale=this.props.scaleY;const newScale=+e.target.value||editorDefaults.scaleY;const scale=function(value){return value*newScale/oldScale};const maxY=scale(this.props.maxY);this.props.onChange({scaleY:newScale,maxY:maxY,correct:_.map(this.props.correct,scale),starting:_.map(this.props.starting,scale)});ReactDOM.findDOMNode(this.refs.maxY).value=maxY;},this.changeMax=e=>{this.props.onChange({maxY:+e.target.value||editorDefaults.maxY});},this.changeSnaps=e=>{this.props.onChange({snapsPerLine:+e.target.value||editorDefaults.snapsPerLine});},this.changeEditing=editing=>{this.setState({editing:editing});},this.setCategoriesFromScale=()=>{const scale=this.state.tickStep||1;const min=this.state.minX||0;const max=this.state.maxX||0;const length=Math.floor((max-min)/scale)*scale;let categories;if(this.props.type==="histogram"||this.props.type==="dotplot"){categories=_.range(0,length+scale,scale);}else {categories=_.range(scale,length+scale,scale);}categories=_.map(categories,num=>num+min);categories=_.map(categories,formatNumber);this.changeCategories(categories);const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");},this.serialize=()=>{const json=_.pick(this.props,"correct","starting","type","labels","categories","scaleY","maxY","snapsPerLine","labelInterval");if(this.props.type==="pic"){json.picUrl=this.props.picUrl;}return json};}}PlotterEditor.widgetName="plotter";PlotterEditor.defaultProps=plotterLogic.defaultWidgetOptions;
1723
+ const{InfoTip: InfoTip$2,NumberInput: NumberInput$2,RangeInput,TextListEditor: TextListEditor$1}=components;const Plotter=PlotterWidget.widget;const STARTING="starting";const CORRECT="correct";const editingStates=[STARTING,CORRECT];function padArray(array,n,value){const copy=_.clone(array);copy.length=n;for(let i=array.length;i<n;i++){copy[i]=value;}return copy}const editorDefaults={scaleY:1,maxY:10,snapsPerLine:2};const formatNumber=num=>"$"+number.round(num,2)+"$";class PlotterEditor extends React.Component{UNSAFE_componentWillMount(){this.fetchPic(this.props.picUrl);}UNSAFE_componentWillReceiveProps(nextProps){this.fetchPic(nextProps.picUrl);if(nextProps.static){this.setState({editing:"starting"});}}render(){const setFromScale=_.contains(["line","histogram","dotplot"],this.props.type);const canChangeSnaps=!_.contains(["pic","dotplot"],this.props.type);const plotterProps={...this.props,trackInteraction:()=>{},starting:this.props[this.state.editing],onChange:this.handlePlotterChange,userInput:this.props.correct,handleUserInput:userInput=>{this.props.onChange({correct:userInput});}};return jsxRuntimeExports.jsxs("div",{className:"perseus-widget-plotter-editor",children:[jsxRuntimeExports.jsxs("div",{children:["Chart type:"," ",plotterPlotTypes.map(type=>{return jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",name:"chart-type",checked:this.props.type===type,onChange:_.partial(this.changeType,type)}),type]},type)},this)]}),jsxRuntimeExports.jsxs("div",{children:["Labels:"," ",["x","y"].map((axis,i)=>{return jsxRuntimeExports.jsxs("label",{children:[axis+":",jsxRuntimeExports.jsx("input",{type:"text",onChange:_.partial(this.changeLabel,i),defaultValue:this.props.labels[i]})]},axis)},this)]}),setFromScale&&jsxRuntimeExports.jsxs("div",{className:"set-from-scale-box",children:[jsxRuntimeExports.jsx("span",{className:"categories-title",children:"Set Categories From Scale"}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Tick Step:"," ",jsxRuntimeExports.jsx(NumberInput$2,{placeholder:1,useArrowKeys:true,value:this.state.tickStep,onChange:this.handleChangeTickStep})]}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"The difference between adjacent ticks."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Range:"," ",jsxRuntimeExports.jsx(RangeInput,{placeholder:[0,10],useArrowKeys:true,value:[this.state.minX,this.state.maxX],onChange:this.handleChangeRange})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("button",{onClick:this.setCategoriesFromScale,children:["Set Categories"," "]})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Label Interval:"," ",jsxRuntimeExports.jsx(NumberInput$2,{useArrowKeys:true,value:this.props.labelInterval,onChange:this.changeLabelInterval})]}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:'Which ticks to display the labels for. For instance, setting this to "4" will only show every 4th label (plus the last one)'})})]}),this.props.type==="pic"&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Picture:"," ",jsxRuntimeExports.jsx(BlurInput,{className:"pic-url",value:this.props.picUrl,onChange:this.changePicUrl}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:'Use the default picture of Earth, or insert the URL for a different picture using the "Add image" function.'})})]}),this.state.pic&&this.state.pic.width!==this.state.pic.height&&jsxRuntimeExports.jsxs("p",{className:"warning",children:[jsxRuntimeExports.jsx("b",{children:"Warning"}),": You are using a picture which is not square. This means the image will get distorted. You should probably crop it to be square."]})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Categories:"," ",jsxRuntimeExports.jsx(TextListEditor$1,{ref:"categories",layout:"horizontal",options:this.props.categories,onChange:this.changeCategories})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Scale (y):"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeScale,defaultValue:this.props.scaleY})]})}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["Max y:"," ",jsxRuntimeExports.jsx("input",{type:"text",ref:"maxY",onChange:this.changeMax,defaultValue:this.props.maxY})]})}),canChangeSnaps&&jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["Snaps per line:"," ",jsxRuntimeExports.jsx("input",{type:"text",onChange:this.changeSnaps,defaultValue:this.props.snapsPerLine})]}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"Creates the specified number of divisions between the horizontal lines. Fewer snaps between lines makes the graph easier for the student to create correctly."})})]}),jsxRuntimeExports.jsxs("div",{children:["Editing values:"," ",editingStates.map(editing=>jsxRuntimeExports.jsxs("label",{children:[jsxRuntimeExports.jsx("input",{type:"radio",disabled:editing===CORRECT&&this.props.static,checked:this.props.static?editing===STARTING:this.state.editing===editing,onChange:e=>this.changeEditing(editing)}),editing]},editing)),jsxRuntimeExports.jsxs(InfoTip$2,{children:[jsxRuntimeExports.jsx("p",{children:"Use this toggle to switch between editing the correct answer (what the student will be graded on) and the starting values (what the student will see plotted when they start the problem). Note: These cannot be the same."}),jsxRuntimeExports.jsx("p",{children:"In static mode, the starting values are rendered out to the displayed widget."})]})]}),jsxRuntimeExports.jsx(Plotter,{...plotterProps})]})}constructor(...args){super(...args),this.state={editing:this.props.static?STARTING:CORRECT,pic:null,loadedUrl:null,minX:null,maxX:null,tickStep:null},this.fetchPic=url=>{if(this.state.loadedUrl!==url){const pic=new Image;pic.src=url;pic.onload=()=>{this.setState({pic:pic,loadedUrl:url});};}},this.handleChangeTickStep=value=>{this.setState({tickStep:value});},this.handleChangeRange=newValue=>{this.setState({minX:newValue[0],maxX:newValue[1]});},this.changeLabelInterval=value=>{this.props.onChange({labelInterval:value});},this.handlePlotterChange=newProps=>{const props={};props[this.state.editing]=newProps.values;this.props.onChange(props);},this.changeType=type=>{let categories;if(type==="histogram"){categories=[formatNumber(0)].concat(this.props.categories);this.props.onChange({type:type,categories:categories});}else if(this.props.type==="histogram"){categories=this.props.categories.slice(1);this.props.onChange({type:type,categories:categories});}else {this.props.onChange({type:type});}if(categories){const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");}},this.changeLabel=(i,e)=>{const labels=_.clone(this.props.labels);labels[i]=e.target.value;this.props.onChange({labels:labels});},this.changePicUrl=value=>{const url=Util.getRealImageUrl(value);this.props.onChange({picUrl:url});},this.changeCategories=categories=>{let n=categories.length;if(this.props.type==="histogram"){n--;}const value=this.props.scaleY;this.props.onChange({categories:categories,correct:padArray(this.props.correct,n,value),starting:padArray(this.props.starting,n,value)});},this.changeScale=e=>{const oldScale=this.props.scaleY;const newScale=+e.target.value||editorDefaults.scaleY;const scale=function(value){return value*newScale/oldScale};const maxY=scale(this.props.maxY);this.props.onChange({scaleY:newScale,maxY:maxY,correct:_.map(this.props.correct,scale),starting:_.map(this.props.starting,scale)});ReactDOM.findDOMNode(this.refs.maxY).value=maxY;},this.changeMax=e=>{this.props.onChange({maxY:+e.target.value||editorDefaults.maxY});},this.changeSnaps=e=>{this.props.onChange({snapsPerLine:+e.target.value||editorDefaults.snapsPerLine});},this.changeEditing=editing=>{this.setState({editing:editing});},this.setCategoriesFromScale=()=>{const scale=this.state.tickStep||1;const min=this.state.minX||0;const max=this.state.maxX||0;const length=Math.floor((max-min)/scale)*scale;let categories;if(this.props.type==="histogram"||this.props.type==="dotplot"){categories=_.range(0,length+scale,scale);}else {categories=_.range(scale,length+scale,scale);}categories=_.map(categories,num=>num+min);categories=_.map(categories,formatNumber);this.changeCategories(categories);const node=ReactDOM.findDOMNode(this.refs.categories);node.value=categories.join(", ");},this.serialize=()=>{const json=_.pick(this.props,"correct","starting","type","labels","categories","scaleY","maxY","snapsPerLine","labelInterval");if(this.props.type==="pic"){json.picUrl=this.props.picUrl;}return json};}}PlotterEditor.widgetName="plotter";PlotterEditor.defaultProps=plotterLogic.defaultWidgetOptions;
1722
1724
 
1723
1725
  const{NumberInput: NumberInput$1,TextInput}=components;function validateOptions(height,programID){const errors=[];if(programID===""){errors.push("The program ID is required.");}if(!Number.isInteger(height)||height<1){errors.push("The height must be a positive integer.");}return errors}class PythonProgramEditor extends React.Component{serialize(){return {programID:this.props.programID,height:this.props.height}}render(){return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:["User Program ID:"," ",jsxRuntimeExports.jsx(TextInput,{value:this.props.programID,onChange:this.change("programID"),placeholder:"123"})]}),jsxRuntimeExports.jsx("br",{}),jsxRuntimeExports.jsxs("label",{children:["Height:"," ",jsxRuntimeExports.jsx(NumberInput$1,{value:this.props.height,onChange:this.change("height"),placeholder:"400"})]})]})}constructor(...args){super(...args),this.change=(...args)=>{return Changeable.change.apply(this,args)},this.getSaveWarnings=()=>{return validateOptions(this.props.height,this.props.programID)};}}PythonProgramEditor.widgetName="python-program";PythonProgramEditor.defaultProps=pythonProgramLogic.defaultWidgetOptions;
1724
1726
 
1725
1727
  var styles = {"tile":"perseus_fAVMAcnB","radioOptionActionsContainer":"perseus_qMTuHJ53","buttonRow":"perseus_FUUSHyqm","imageEditorContainer":"perseus_JUItwJjV"};
1726
1728
 
1727
- function RadioImageEditor({initialImageUrl,initialImageAltText,containerClassName,onSave,onClose,onDelete}){const[imageUrl,setImageUrl]=React.useState(initialImageUrl);const[imageAltText,setImageAltText]=React.useState(initialImageAltText);React.useEffect(()=>{setImageUrl(initialImageUrl??"");setImageAltText(initialImageAltText??"");},[initialImageUrl,initialImageAltText]);const uniqueId=React.useId();const imageUrlTextAreaId=`${uniqueId}-image-url-textarea`;const imageAltTextTextAreaId=`${uniqueId}-image-alt-text-textarea`;function handleClose(){setImageUrl("");setImageAltText("");onClose?.();}function handleSave(){onSave(imageUrl,imageAltText);handleClose();}return jsxRuntimeExports.jsxs("div",{className:containerClassName,children:[onClose&&jsxRuntimeExports.jsx(IconButton,{"aria-label":"Close",icon:xIcon,size:"small",kind:"tertiary",onClick:handleClose,style:{position:"absolute",top:4,right:4}}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:imageUrlTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Image URL"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:imageUrlTextAreaId,value:imageUrl,placeholder:"cdn.kastatic.org/...",onChange:value=>{setImageUrl(value);},style:{marginBlockEnd:sizing.size_080}}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:imageAltTextTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Image Alt Text"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:imageAltTextTextAreaId,value:imageAltText,placeholder:"Example: Graph of a linear function...",onChange:value=>{setImageAltText(value);}}),jsxRuntimeExports.jsxs("span",{className:styles.buttonRow,children:[onDelete&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:trashIcon,style:{alignSelf:"flex-start"},onClick:onDelete,children:"Delete this image"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(Button,{size:"small",disabled:imageUrl===initialImageUrl&&imageAltText===initialImageAltText,style:{alignSelf:"flex-start"},onClick:handleSave,children:"Save image"})]})]})}
1729
+ function RadioImageEditor({initialImageUrl,initialImageAltText,initialImageWidth,initialImageHeight,containerClassName,onSave,onClose,onDelete}){const[imageUrl,setImageUrl]=React.useState(initialImageUrl);const[imageAltText,setImageAltText]=React.useState(initialImageAltText);const[imageWidth,setImageWidth]=React.useState(initialImageWidth);const[imageHeight,setImageHeight]=React.useState(initialImageHeight);React.useEffect(()=>{setImageUrl(initialImageUrl??"");setImageAltText(initialImageAltText??"");setImageWidth(initialImageWidth);setImageHeight(initialImageHeight);},[initialImageUrl,initialImageAltText,initialImageWidth,initialImageHeight]);const uniqueId=React.useId();const imageUrlTextAreaId=`${uniqueId}-image-url-textarea`;const imageAltTextTextAreaId=`${uniqueId}-image-alt-text-textarea`;React.useEffect(()=>{async function fetchDimensions(){if(!imageUrl){setImageWidth(undefined);setImageHeight(undefined);return}try{const size=await Util.getImageSizeModern(imageUrl);setImageWidth(size[0]);setImageHeight(size[1]);}catch(error){setImageWidth(undefined);setImageHeight(undefined);}}if(imageUrl!==initialImageUrl){void fetchDimensions();}},[imageUrl,initialImageUrl]);function handleClose(){setImageUrl("");setImageAltText("");setImageWidth(undefined);setImageHeight(undefined);onClose?.();}function handleSave(){onSave(imageUrl,imageAltText,imageWidth,imageHeight);handleClose();}return jsxRuntimeExports.jsxs("div",{className:containerClassName,children:[onClose&&jsxRuntimeExports.jsx(IconButton,{"aria-label":"Close",icon:xIcon,size:"small",kind:"tertiary",onClick:handleClose,style:{position:"absolute",top:4,right:4}}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:imageUrlTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Image URL"}),jsxRuntimeExports.jsx(TextArea,{id:imageUrlTextAreaId,value:imageUrl,placeholder:"cdn.kastatic.org/...",onChange:value=>{setImageUrl(value);},style:{marginBlockEnd:sizing.size_080},autoResize:true}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:imageAltTextTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Image Alt Text"}),jsxRuntimeExports.jsx(TextArea,{id:imageAltTextTextAreaId,value:imageAltText,placeholder:"Example: Graph of a linear function...",onChange:value=>{setImageAltText(value);},autoResize:true}),jsxRuntimeExports.jsxs("span",{className:styles.buttonRow,children:[onDelete&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:trashIcon,style:{alignSelf:"flex-start"},onClick:onDelete,children:"Delete this image"}),jsxRuntimeExports.jsx(Spring,{}),jsxRuntimeExports.jsx(Button,{size:"small",disabled:imageUrl===initialImageUrl&&imageAltText===initialImageAltText,style:{alignSelf:"flex-start"},onClick:handleSave,children:"Save image"})]})]})}
1728
1730
 
1729
1731
  function getMovedChoices(choices,hasNoneOfTheAbove,choiceIndex,movement){const newChoices=[...choices];const[removedChoice]=newChoices.splice(choiceIndex,1);switch(movement){case "top":if(choiceIndex===0){return choices}newChoices.unshift(removedChoice);break;case "up":if(choiceIndex===0){return choices}newChoices.splice(choiceIndex-1,0,removedChoice);break;case "down":if(choiceIndex===choices.length-1){return choices}if(choiceIndex===choices.length-2&&hasNoneOfTheAbove){return choices}newChoices.splice(choiceIndex+1,0,removedChoice);break;case "bottom":if(choiceIndex===choices.length-1){return choices}if(hasNoneOfTheAbove){const removedNoneOfTheAbove=newChoices.pop();newChoices.push(removedChoice);if(removedNoneOfTheAbove){newChoices.push(removedNoneOfTheAbove);}}else {newChoices.push(removedChoice);}break}return newChoices}function setImageProxyFromMarkdownContent(markdownContent){const images=[];const parsedMarkdown=PerseusMarkdown.parse(markdownContent,{});PerseusMarkdown.traverseContent(parsedMarkdown,node=>{if(node.type==="image"){images.push({url:node.target||"",altText:node.alt||""});}});let proxiedContent=markdownContent;images.forEach((image,index)=>{const originalPattern=`![${image.altText}](${image.url})`;const replacement=`![Image ${index+1}]`;const patternIndex=proxiedContent.indexOf(originalPattern);if(patternIndex!==-1){proxiedContent=proxiedContent.substring(0,patternIndex)+replacement+proxiedContent.substring(patternIndex+originalPattern.length);}});return [proxiedContent,images]}function setMarkdownContentFromImageProxy(proxiedContent,images){let markdownContent=proxiedContent;for(let i=0;i<images.length;i++){const image=images[i];markdownContent=markdownContent.replace(`![Image ${i+1}]`,`![${image.altText}](${image.url})`);}return markdownContent}
1730
1732
 
1731
- const{SvgImage}=components;const RadioOptionContentAndImageEditor=props=>{const{content,choiceIndex,onContentChange,isNoneOfTheAbove}=props;const uniqueId=React.useId();const contentTextAreaId=`${uniqueId}-content-textarea`;const[proxiedContent,setProxiedContent]=React.useState("");const[images,setImages]=React.useState([]);const[addingImage,setAddingImage]=React.useState(false);React.useEffect(()=>{const[proxiedContent,images]=setImageProxyFromMarkdownContent(content??"");setProxiedContent(proxiedContent);setImages(images);},[content]);const handleAddImage=(choiceIndex,imageUrl,imageAltText)=>{const newContent=`${content}
1732
- ![${imageAltText}](${imageUrl})`;onContentChange(choiceIndex,newContent);};const handleDeleteImage=imageIndex=>{const substr=`![Image ${imageIndex+1}]`;const newProxiedContent=proxiedContent.replace(substr,"");setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handleUpdateImage=(imageIndex,url,altText)=>{const newImages=[...images];newImages[imageIndex]={url,altText};setImages(newImages);const newContent=setMarkdownContentFromImageProxy(proxiedContent,newImages);onContentChange(choiceIndex,newContent);};const handleContentChange=(choiceIndex,newProxiedContent)=>{setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handlePaste=e=>{const imageURL=e.clipboardData.getData("text");if(imageURL.includes("cdn.kastatic.org")||imageURL.includes("graphie")){e.preventDefault();handleAddImage(choiceIndex,imageURL,"");}};const handleDeleteImageConfirmation=imageIndex=>{if(window.confirm("Are you sure you want to delete this image?")){handleDeleteImage(imageIndex);}};if(isNoneOfTheAbove){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,children:"Content"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:contentTextAreaId,value:"None of the above",disabled:true,onChange:()=>{}})]})}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Content"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:contentTextAreaId,value:proxiedContent,placeholder:"Type a choice here...",onChange:value=>{handleContentChange(choiceIndex,value);},onPaste:handlePaste}),!addingImage&&jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,size:"small",kind:"tertiary",style:{alignSelf:"flex-start"},onClick:()=>{setAddingImage(true);},children:"Add image"}),addingImage&&jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:"",initialImageAltText:"",containerClassName:styles.imageEditorContainer,onSave:(imageUrl,imageAltText)=>{handleAddImage(choiceIndex,imageUrl,imageAltText);},onClose:()=>{setAddingImage(false);}}),images?.map((image,imageIndex)=>jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:`Image ${imageIndex+1}`,expanded:true,containerStyle:{backgroundColor:semanticColor.core.background.base.default,marginBlockStart:sizing.size_040,marginBlockEnd:sizing.size_040},panelStyle:{paddingBlockEnd:sizing.size_120},children:[jsxRuntimeExports.jsx(SvgImage,{src:image.url,alt:`Preview: ${image.altText??"No alt text"}`,allowZoom:false}),jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:image.url,initialImageAltText:image.altText,onSave:(imageUrl,imageAltText)=>{handleUpdateImage(imageIndex,imageUrl,imageAltText);},onDelete:()=>{handleDeleteImageConfirmation(imageIndex);}})]},image.url))??null]})};
1733
+ const RadioOptionContentAndImageEditor=props=>{const{content,choiceIndex,onContentChange,isNoneOfTheAbove}=props;const uniqueId=React.useId();const contentTextAreaId=`${uniqueId}-content-textarea`;const[proxiedContent,setProxiedContent]=React.useState("");const[images,setImages]=React.useState([]);const[addingImage,setAddingImage]=React.useState(false);React.useEffect(()=>{const[proxiedContent,parsedImages]=setImageProxyFromMarkdownContent(content??"");setProxiedContent(proxiedContent);setImages(parsedImages);async function fetchAllDimensions(){const imagesWithDimensions=await Promise.all(parsedImages.map(async image=>{try{const size=await Util.getImageSizeModern(image.url);return {...image,width:size[0],height:size[1]}}catch(error){return image}}));setImages(imagesWithDimensions);}void fetchAllDimensions();},[content]);const handleAddImage=(choiceIndex,imageUrl,imageAltText,width,height)=>{const newContent=`${content}
1734
+ ![${imageAltText}](${imageUrl})`;onContentChange(choiceIndex,newContent);};const handleDeleteImage=imageIndex=>{const substr=`![Image ${imageIndex+1}]`;const newProxiedContent=proxiedContent.replace(substr,"");setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handleUpdateImage=(imageIndex,url,altText,width,height)=>{const newImages=[...images];newImages[imageIndex]={url,altText,width,height};setImages(newImages);const newContent=setMarkdownContentFromImageProxy(proxiedContent,newImages);onContentChange(choiceIndex,newContent);};const handleContentChange=(choiceIndex,newProxiedContent)=>{setProxiedContent(newProxiedContent);const newContent=setMarkdownContentFromImageProxy(newProxiedContent,images);onContentChange(choiceIndex,newContent);};const handlePaste=e=>{const imageURL=e.clipboardData.getData("text");if(imageURL.includes("cdn.kastatic.org")||imageURL.includes("graphie")){e.preventDefault();handleAddImage(choiceIndex,imageURL,"");}};const handleDeleteImageConfirmation=imageIndex=>{if(window.confirm("Are you sure you want to delete this image?")){handleDeleteImage(imageIndex);}};if(isNoneOfTheAbove){return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,children:"Content"}),jsxRuntimeExports.jsx(TextArea,{id:contentTextAreaId,value:"None of the above",disabled:true,onChange:()=>{},autoResize:true})]})}return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:contentTextAreaId,style:{marginBlockEnd:sizing.size_040},children:"Content"}),jsxRuntimeExports.jsx(TextArea,{id:contentTextAreaId,value:proxiedContent,placeholder:"Type a choice here...",onChange:value=>{handleContentChange(choiceIndex,value);},onPaste:handlePaste,autoResize:true}),!addingImage&&jsxRuntimeExports.jsx(Button,{startIcon:plusIcon,size:"small",kind:"tertiary",style:{alignSelf:"flex-start"},onClick:()=>{setAddingImage(true);},children:"Add image"}),addingImage&&jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:"",initialImageAltText:"",containerClassName:styles.imageEditorContainer,onSave:(imageUrl,imageAltText,width,height)=>{handleAddImage(choiceIndex,imageUrl,imageAltText);},onClose:()=>{setAddingImage(false);}}),images?.map((image,imageIndex)=>jsxRuntimeExports.jsxs(PerseusEditorAccordion,{header:`Image ${imageIndex+1}`,expanded:true,containerStyle:{backgroundColor:semanticColor.core.background.base.default,marginBlockStart:sizing.size_040,marginBlockEnd:sizing.size_040},panelStyle:{paddingBlockEnd:sizing.size_120},children:[jsxRuntimeExports.jsx(LabeledField,{label:"Preview",field:jsxRuntimeExports.jsx(ImagePreview,{src:image.url,alt:`Preview: ${image.altText??"No alt text"}`,width:image.width,height:image.height})}),jsxRuntimeExports.jsx("div",{style:{marginTop:sizing.size_160},children:jsxRuntimeExports.jsx(RadioImageEditor,{initialImageUrl:image.url,initialImageAltText:image.altText,initialImageWidth:image.width,initialImageHeight:image.height,onSave:(imageUrl,imageAltText,width,height)=>{handleUpdateImage(imageIndex,imageUrl,imageAltText,width,height);},onDelete:()=>{handleDeleteImageConfirmation(imageIndex);}})})]},image.url))??null]})};
1733
1735
 
1734
1736
  function RadioOptionSettingsActions({content,showDelete,showMove,onDelete,onMove}){return jsxRuntimeExports.jsxs("div",{className:styles.radioOptionActionsContainer,children:[showDelete&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:trashIcon,onClick:()=>{if(window.confirm(`Are you sure you want to remove this choice?
1735
1737
 
@@ -1737,15 +1739,17 @@ ${content}`)){onDelete();}},children:"Remove"}),showMove&&jsxRuntimeExports.jsxs
1737
1739
 
1738
1740
  function RadioStatusPill({index,correct,multipleSelect,onClick}){return jsxRuntimeExports.jsx(Pill,{size:"large",style:{marginInlineEnd:sizing.size_080,color:correct?color.white:color.red,backgroundColor:correct?color.activeGreen:color.fadedRed8,borderRadius:multipleSelect?border.radius.radius_040:sizing.size_240,border:`1px solid ${correct?color.activeGreen:color.red}`,width:sizing.size_560,flexDirection:"row"},onClick:onClick,children:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(PhosphorIcon,{size:"small",icon:correct?checkIcon:minusCircleIcon,style:{marginInlineEnd:sizing.size_060},color:correct?color.white:color.red}),String.fromCharCode(65+index)]})})}
1739
1741
 
1740
- function RadioOptionSettings({index,choice,multipleSelect,onStatusChange,onContentChange,onRationaleChange,showDelete,showMove,onDelete,onMove}){const{content,rationale,correct,isNoneOfTheAbove}=choice;const uniqueId=React.useId();const rationaleTextAreaId=`${uniqueId}-rationale-textarea`;return jsxRuntimeExports.jsxs("div",{className:styles.tile,children:[jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(RadioStatusPill,{index:index,correct:correct,multipleSelect:multipleSelect,onClick:()=>{onStatusChange(index,!correct);}}),jsxRuntimeExports.jsx(HeadingXSmall,{style:{display:"inline",marginInlineEnd:sizing.size_080},children:"Status"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"accent":"transparent",onClick:()=>{onStatusChange(index,true);},style:{marginInlineEnd:sizing.size_080,outlineColor:correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Correct"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"transparent":"accent",onClick:()=>{onStatusChange(index,false);},style:{marginInlineEnd:sizing.size_080,outlineColor:!correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Incorrect"})]}),jsxRuntimeExports.jsx(RadioOptionContentAndImageEditor,{content:content,choiceIndex:index,isNoneOfTheAbove:isNoneOfTheAbove??false,onContentChange:onContentChange}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:rationaleTextAreaId,style:{marginBlockStart:sizing.size_040,marginBlockEnd:sizing.size_040},children:"Rationale"}),jsxRuntimeExports.jsx(AutoResizingTextArea,{id:rationaleTextAreaId,value:rationale??"",placeholder:`Why is this choice ${correct?"correct":"incorrect"}?`,onChange:value=>{onRationaleChange(index,value);}}),jsxRuntimeExports.jsx(RadioOptionSettingsActions,{content:content,showDelete:showDelete,showMove:showMove,onDelete:onDelete,onMove:movement=>onMove(index,movement)})]})}
1742
+ function RadioOptionSettings({index,choice,multipleSelect,onStatusChange,onContentChange,onRationaleChange,showDelete,showMove,onDelete,onMove}){const{content,rationale,correct,isNoneOfTheAbove}=choice;const uniqueId=React.useId();const rationaleTextAreaId=`${uniqueId}-rationale-textarea`;return jsxRuntimeExports.jsxs("div",{className:styles.tile,children:[jsxRuntimeExports.jsxs("fieldset",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(RadioStatusPill,{index:index,correct:correct,multipleSelect:multipleSelect,onClick:()=>{onStatusChange(index,!correct);}}),jsxRuntimeExports.jsx(HeadingXSmall,{style:{display:"inline",marginInlineEnd:sizing.size_080},children:"Status"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"accent":"transparent",onClick:()=>{onStatusChange(index,true);},style:{marginInlineEnd:sizing.size_080,outlineColor:correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Correct"}),jsxRuntimeExports.jsx(Pill,{kind:correct?"transparent":"accent",onClick:()=>{onStatusChange(index,false);},style:{marginInlineEnd:sizing.size_080,outlineColor:!correct?semanticColor.core.background.instructive.default:semanticColor.core.border.neutral.default},children:"Incorrect"})]}),jsxRuntimeExports.jsx(RadioOptionContentAndImageEditor,{content:content,choiceIndex:index,isNoneOfTheAbove:isNoneOfTheAbove??false,onContentChange:onContentChange}),jsxRuntimeExports.jsx(HeadingXSmall,{tag:"label",htmlFor:rationaleTextAreaId,style:{marginBlockStart:sizing.size_040,marginBlockEnd:sizing.size_040},children:"Rationale"}),jsxRuntimeExports.jsx(TextArea,{id:rationaleTextAreaId,value:rationale??"",placeholder:`Why is this choice ${correct?"correct":"incorrect"}?`,onChange:value=>{onRationaleChange(index,value);},autoResize:true}),jsxRuntimeExports.jsx(RadioOptionSettingsActions,{content:content,showDelete:showDelete,showMove:showMove,onDelete:onDelete,onMove:movement=>onMove(index,movement)})]})}
1743
+
1744
+ class RadioEditor extends React.Component{componentDidMount(){if(this.props.multipleSelect&&this.props.countChoices){this.props.onChange({numCorrect:deriveNumCorrect(this.props.choices)});}const needsIdUpdate=this.props.choices.some(choice=>!choice.id||choice.id.trim()==="");if(needsIdUpdate){const updatedChoices=this.props.choices.map((choice,index)=>({...choice,id:this.ensureValidIds(choice.id,index)}));this.props.onChange({choices:updatedChoices});}}serialize(){const{choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled}=this.props;return {choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled,numCorrect:deriveNumCorrect(choices)}}render(){const numCorrect=deriveNumCorrect(this.props.choices);const isEditingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Link$1,{href:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",target:"_blank",children:"Multiple choice best practices"}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Randomize order",checked:this.props.randomize,disabled:isEditingDisabled,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"Multiple selections",checked:this.props.multipleSelect,disabled:isEditingDisabled,onChange:value=>{this.onMultipleSelectChange({multipleSelect:value});},style:{marginBlockEnd:sizing.size_060}}),this.props.multipleSelect&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Specify number correct",checked:this.props.countChoices,disabled:isEditingDisabled,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsxs(Footnote,{children:["Current number correct: ",numCorrect]})]})]}),this.props.choices.map((choice,index)=>jsxRuntimeExports.jsx(RadioOptionSettings,{index:index,choice:choice,multipleSelect:this.props.multipleSelect,onStatusChange:this.onStatusChange,onContentChange:this.onContentChange,onRationaleChange:this.onRationaleChange,showDelete:this.props.choices.length>=2,showMove:this.props.choices.length>1&&!choice.isNoneOfTheAbove,onDelete:()=>this.onDelete(index),onMove:this.handleMove},`choice-${choice.id}}`)),jsxRuntimeExports.jsxs("div",{className:"add-choice-container",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,false),style:{marginInlineEnd:"2.4rem"},children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,true),children:"None of the above"})]})]})}constructor(...args){super(...args),this.onMultipleSelectChange=allowMultiple=>{const isMultipleSelect=allowMultiple.multipleSelect;let choices=this.props.choices;if(!isMultipleSelect){const numCorrect=deriveNumCorrect(choices);if(numCorrect>1){choices=choices.map(choice=>{return {...choice,correct:false}});}}this.props.onChange({multipleSelect:isMultipleSelect,choices,numCorrect:deriveNumCorrect(choices)});},this.onCountChoicesChange=count=>{const countChoices=count.countChoices;this.props.onChange({countChoices});},this.generateChoiceId=index=>{return `radio-choice-${index}`},this.ensureValidIds=(choiceId,index)=>{if(!choiceId||choiceId.trim()===""){return this.generateChoiceId(index)}return choiceId},this.onChange=({checked})=>{const choices=this.props.choices.map((choice,i)=>{return {...choice,correct:checked[i],content:choice.isNoneOfTheAbove&&!checked[i]?"":choice.content,id:this.ensureValidIds(choice.id,i)}});this.props.onChange({choices,numCorrect:deriveNumCorrect(choices)});},this.onStatusChange=(choiceIndex,correct)=>{let newCheckedList;if(correct&&!this.props.multipleSelect){newCheckedList=this.props.choices.map(_=>false);}else {newCheckedList=this.props.choices.map(c=>c.correct);}newCheckedList[choiceIndex]=correct;this.onChange({checked:newCheckedList});},this.onContentChange=(choiceIndex,newContent)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],content:newContent};this.props.onChange({choices:choices});},this.onRationaleChange=(choiceIndex,newRationale)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],rationale:newRationale};if(newRationale===""){delete choices[choiceIndex].rationale;}this.props.onChange({choices:choices});},this.onDelete=choiceIndex=>{const choices=this.props.choices.slice();const deleted=choices[choiceIndex];choices.splice(choiceIndex,1);this.props.onChange({choices,hasNoneOfTheAbove:this.props.hasNoneOfTheAbove&&!deleted.isNoneOfTheAbove,numCorrect:deriveNumCorrect(choices)});},this.addChoice=(noneOfTheAbove,e)=>{e.preventDefault();const choices=this.props.choices.slice();const newChoice={isNoneOfTheAbove:noneOfTheAbove,content:"",id:crypto.randomUUID()};const addIndex=choices.length-(this.props.hasNoneOfTheAbove?1:0);choices.splice(addIndex,0,newChoice);this.props.onChange({choices:choices,hasNoneOfTheAbove:noneOfTheAbove||this.props.hasNoneOfTheAbove},()=>{this.refs[`choice-editor${addIndex}`].refs["content-editor"].focus();});},this.handleMove=(choiceIndex,movement)=>{const newChoices=getMovedChoices(this.props.choices,this.props.hasNoneOfTheAbove,choiceIndex,movement);this.props.onChange({choices:newChoices});},this.focus=()=>{this.refs["choice-editor0"].refs["content-editor"].focus();return true},this.getSaveWarnings=()=>{if(!_.some(_.pluck(this.props.choices,"correct"))){return ["No choice is marked as correct."]}return []};}}RadioEditor.widgetName="radio";RadioEditor.defaultProps=radioLogic.defaultWidgetOptions;
1741
1745
 
1742
- class RadioEditor extends React.Component{componentDidMount(){const needsIdUpdate=this.props.choices.some(choice=>!choice.id||choice.id.trim()==="");if(needsIdUpdate){const updatedChoices=this.props.choices.map((choice,index)=>({...choice,id:this.ensureValidIds(choice.id,index)}));this.props.onChange({choices:updatedChoices});}}serialize(){const{choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled}=this.props;return {choices,randomize,multipleSelect,countChoices,hasNoneOfTheAbove,deselectEnabled,numCorrect:deriveNumCorrect(choices)}}render(){const numCorrect=deriveNumCorrect(this.props.choices);const isEditingDisabled=this.props.apiOptions.editingDisabled;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Link$1,{href:"https://www.khanacademy.org/internal-courses/content-creation-best-practices/xe46daa512cd9c644:question-writing/xe46daa512cd9c644:multiple-choice/a/stems",target:"_blank",children:"Multiple choice best practices"}),jsxRuntimeExports.jsxs("div",{className:"perseus-widget-row",children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Randomize order",checked:this.props.randomize,disabled:isEditingDisabled,onChange:value=>{this.props.onChange({randomize:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsx(LabeledSwitch,{label:"Multiple selections",checked:this.props.multipleSelect,disabled:isEditingDisabled,onChange:value=>{this.onMultipleSelectChange({multipleSelect:value});},style:{marginBlockEnd:sizing.size_060}}),this.props.multipleSelect&&jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledSwitch,{label:"Specify number correct",checked:this.props.countChoices,disabled:isEditingDisabled,onChange:value=>{this.onCountChoicesChange({countChoices:value});},style:{marginBlockEnd:sizing.size_060}}),jsxRuntimeExports.jsxs(Footnote,{children:["Current number correct: ",numCorrect]})]})]}),this.props.choices.map((choice,index)=>jsxRuntimeExports.jsx(RadioOptionSettings,{index:index,choice:choice,multipleSelect:this.props.multipleSelect,onStatusChange:this.onStatusChange,onContentChange:this.onContentChange,onRationaleChange:this.onRationaleChange,showDelete:this.props.choices.length>=2,showMove:this.props.choices.length>1&&!choice.isNoneOfTheAbove,onDelete:()=>this.onDelete(index),onMove:this.handleMove},`choice-${choice.id}}`)),jsxRuntimeExports.jsxs("div",{className:"add-choice-container",children:[jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,false),style:{marginInlineEnd:"2.4rem"},children:"Add a choice"}),!this.props.hasNoneOfTheAbove&&jsxRuntimeExports.jsx(Button,{size:"small",kind:"tertiary",startIcon:plusIcon,onClick:this.addChoice.bind(this,true),children:"None of the above"})]})]})}constructor(...args){super(...args),this.onMultipleSelectChange=allowMultiple=>{const isMultipleSelect=allowMultiple.multipleSelect;let choices=this.props.choices;if(!isMultipleSelect){const numCorrect=deriveNumCorrect(choices);if(numCorrect>1){choices=choices.map(choice=>{return {...choice,correct:false}});}}this.props.onChange({multipleSelect:isMultipleSelect,choices,numCorrect:deriveNumCorrect(choices)});},this.onCountChoicesChange=count=>{const countChoices=count.countChoices;this.props.onChange({countChoices});},this.generateChoiceId=index=>{return `radio-choice-${index}`},this.ensureValidIds=(choiceId,index)=>{if(!choiceId||choiceId.trim()===""){return this.generateChoiceId(index)}return choiceId},this.onChange=({checked})=>{const choices=this.props.choices.map((choice,i)=>{return {...choice,correct:checked[i],content:choice.isNoneOfTheAbove&&!checked[i]?"":choice.content,id:this.ensureValidIds(choice.id,i)}});this.props.onChange({choices,numCorrect:deriveNumCorrect(choices)});},this.onStatusChange=(choiceIndex,correct)=>{let newCheckedList;if(correct&&!this.props.multipleSelect){newCheckedList=this.props.choices.map(_=>false);}else {newCheckedList=this.props.choices.map(c=>c.correct);}newCheckedList[choiceIndex]=correct;this.onChange({checked:newCheckedList});},this.onContentChange=(choiceIndex,newContent)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],content:newContent};this.props.onChange({choices:choices});},this.onRationaleChange=(choiceIndex,newRationale)=>{const choices=[...this.props.choices];choices[choiceIndex]={...choices[choiceIndex],rationale:newRationale};if(newRationale===""){delete choices[choiceIndex].rationale;}this.props.onChange({choices:choices});},this.onDelete=choiceIndex=>{const choices=this.props.choices.slice();const deleted=choices[choiceIndex];choices.splice(choiceIndex,1);this.props.onChange({choices,hasNoneOfTheAbove:this.props.hasNoneOfTheAbove&&!deleted.isNoneOfTheAbove,numCorrect:deriveNumCorrect(choices)});},this.addChoice=(noneOfTheAbove,e)=>{e.preventDefault();const choices=this.props.choices.slice();const newChoice={isNoneOfTheAbove:noneOfTheAbove,content:"",id:crypto.randomUUID()};const addIndex=choices.length-(this.props.hasNoneOfTheAbove?1:0);choices.splice(addIndex,0,newChoice);this.props.onChange({choices:choices,hasNoneOfTheAbove:noneOfTheAbove||this.props.hasNoneOfTheAbove},()=>{this.refs[`choice-editor${addIndex}`].refs["content-editor"].focus();});},this.handleMove=(choiceIndex,movement)=>{const newChoices=getMovedChoices(this.props.choices,this.props.hasNoneOfTheAbove,choiceIndex,movement);this.props.onChange({choices:newChoices});},this.focus=()=>{this.refs["choice-editor0"].refs["content-editor"].focus();return true},this.getSaveWarnings=()=>{if(!_.some(_.pluck(this.props.choices,"correct"))){return ["No choice is marked as correct."]}return []};}}RadioEditor.widgetName="radio";RadioEditor.defaultProps=radioLogic.defaultWidgetOptions;
1746
+ const{InfoTip: InfoTip$1,TextListEditor}=components;const HORIZONTAL="horizontal";const VERTICAL="vertical";class SorterEditor extends React.Component{render(){const editor=this;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$1,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answer (in the correct order) here. The preview on the right will have the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.correct,onChange:function(options,cb){editor.props.onChange({correct:options},cb);},layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Layout:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.layout,onChange:this.onLayoutChange,children:[jsxRuntimeExports.jsx("option",{value:HORIZONTAL,children:"Horizontal"}),jsxRuntimeExports.jsx("option",{value:VERTICAL,children:"Vertical"})]})]}),jsxRuntimeExports.jsx(InfoTip$1,{children:jsxRuntimeExports.jsx("p",{children:"Use the horizontal layout for short text and small images. The vertical layout is best for longer text and larger images."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip$1,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLayoutChange=e=>{this.props.onChange({layout:e.target.value});},this.serialize=()=>{return _.pick(this.props,"correct","layout","padding")};}}SorterEditor.propTypes={correct:PropTypes.array,layout:PropTypes.oneOf([HORIZONTAL,VERTICAL]),padding:PropTypes.bool};SorterEditor.widgetName="sorter";SorterEditor.defaultProps=sorterLogic.defaultWidgetOptions;
1743
1747
 
1744
- const{InfoTip: InfoTip$2,TextListEditor}=components;const HORIZONTAL="horizontal";const VERTICAL="vertical";class SorterEditor extends React.Component{render(){const editor=this;return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("div",{children:[" ","Correct answer:"," ",jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"Enter the correct answer (in the correct order) here. The preview on the right will have the cards in a randomized order, which is how the student will see them."})})]}),jsxRuntimeExports.jsx(TextListEditor,{options:this.props.correct,onChange:function(options,cb){editor.props.onChange({correct:options},cb);},layout:this.props.layout}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsxs("label",{children:[" ","Layout:"," ",jsxRuntimeExports.jsxs("select",{value:this.props.layout,onChange:this.onLayoutChange,children:[jsxRuntimeExports.jsx("option",{value:HORIZONTAL,children:"Horizontal"}),jsxRuntimeExports.jsx("option",{value:VERTICAL,children:"Vertical"})]})]}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"Use the horizontal layout for short text and small images. The vertical layout is best for longer text and larger images."})})]}),jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx(Checkbox$1,{label:"Padding:",checked:this.props.padding,onChange:value=>{this.props.onChange({padding:value});}}),jsxRuntimeExports.jsx(InfoTip$2,{children:jsxRuntimeExports.jsx("p",{children:"Padding is good for text, but not needed for images."})})]})]})}constructor(...args){super(...args),this.onLayoutChange=e=>{this.props.onChange({layout:e.target.value});},this.serialize=()=>{return _.pick(this.props,"correct","layout","padding")};}}SorterEditor.propTypes={correct:PropTypes.array,layout:PropTypes.oneOf([HORIZONTAL,VERTICAL]),padding:PropTypes.bool};SorterEditor.widgetName="sorter";SorterEditor.defaultProps=sorterLogic.defaultWidgetOptions;
1748
+ const{InfoTip,NumberInput}=components;const Table=TableWidget.widget;class TableEditor extends React.Component{render(){const tableProps={headers:this.props.headers,onChange:this.props.onChange,userInput:this.props.answers,handleUserInput:userInput=>{if(this.props.apiOptions?.editingDisabled){return}this.props.onChange({answers:userInput});},apiOptions:this.props.apiOptions,editableHeaders:true,onFocus:()=>{},onBlur:()=>{},trackInteraction:()=>{},Editor:Editor};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of columns:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:this.numberOfColumns,value:this.props.columns,onChange:val=>{if(val){this.onSizeInput(this.props.rows,val);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of rows:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:"numberOfRows",value:this.props.rows,onChange:val=>{if(val){this.onSizeInput(val,this.props.columns);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsxs("div",{children:[" ","Table of answers:"," ",jsxRuntimeExports.jsx(InfoTip,{children:jsxRuntimeExports.jsx("p",{children:"The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(Table,{...tableProps})})]})}constructor(...args){super(...args),this.numberOfColumns=React.createRef(),this.focus=()=>{this.numberOfColumns.current?.focus();},this.onSizeInput=(numRawRows,numRawColumns)=>{let rows=+numRawRows||0;let columns=+numRawColumns||0;rows=Math.min(Math.max(1,rows),30);columns=Math.min(Math.max(1,columns),6);const oldColumns=this.props.columns;const oldRows=this.props.rows;const answers=this.props.answers;if(rows<=oldRows){answers.length=rows;}else {_(rows-oldRows).times(function(){answers.push(Util.stringArrayOfSize(oldColumns));});}function fixColumnSizing(array){if(columns<=oldColumns){array.length=columns;}else {_(columns-oldColumns).times(function(){array.push("");});}}const headers=this.props.headers;fixColumnSizing(headers);_.each(answers,fixColumnSizing);this.props.onChange({rows:rows,columns:columns,answers:answers,headers:headers});},this.serialize=()=>{const json=_.pick(this.props,"headers","rows","columns");return _.extend({},json,{answers:_.map(this.props.answers,_.clone)})};}}TableEditor.propTypes={rows:PropTypes.number,columns:PropTypes.number,headers:PropTypes.arrayOf(PropTypes.string),answers:PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string))};TableEditor.widgetName="table";TableEditor.defaultProps=tableLogic.defaultWidgetOptions;
1745
1749
 
1746
- const{InfoTip: InfoTip$1,NumberInput}=components;const Table=TableWidget.widget;class TableEditor extends React.Component{render(){const tableProps={headers:this.props.headers,onChange:this.props.onChange,userInput:this.props.answers,handleUserInput:userInput=>{if(this.props.apiOptions?.editingDisabled){return}this.props.onChange({answers:userInput});},apiOptions:this.props.apiOptions,editableHeaders:true,onFocus:()=>{},onBlur:()=>{},trackInteraction:()=>{},Editor:Editor};return jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of columns:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:this.numberOfColumns,value:this.props.columns,onChange:val=>{if(val){this.onSizeInput(this.props.rows,val);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsx("div",{className:"perseus-widget-row",children:jsxRuntimeExports.jsxs("label",{children:["Number of rows:"," ",jsxRuntimeExports.jsx(NumberInput,{ref:"numberOfRows",value:this.props.rows,onChange:val=>{if(val){this.onSizeInput(val,this.props.columns);}},useArrowKeys:true})]})}),jsxRuntimeExports.jsxs("div",{children:[" ","Table of answers:"," ",jsxRuntimeExports.jsx(InfoTip$1,{children:jsxRuntimeExports.jsx("p",{children:"The student has to fill out all cells in the table. For partially filled tables create a table using the template, and insert text input boxes as desired."})})]}),jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsx(Table,{...tableProps})})]})}constructor(...args){super(...args),this.numberOfColumns=React.createRef(),this.focus=()=>{this.numberOfColumns.current?.focus();},this.onSizeInput=(numRawRows,numRawColumns)=>{let rows=+numRawRows||0;let columns=+numRawColumns||0;rows=Math.min(Math.max(1,rows),30);columns=Math.min(Math.max(1,columns),6);const oldColumns=this.props.columns;const oldRows=this.props.rows;const answers=this.props.answers;if(rows<=oldRows){answers.length=rows;}else {_(rows-oldRows).times(function(){answers.push(Util.stringArrayOfSize(oldColumns));});}function fixColumnSizing(array){if(columns<=oldColumns){array.length=columns;}else {_(columns-oldColumns).times(function(){array.push("");});}}const headers=this.props.headers;fixColumnSizing(headers);_.each(answers,fixColumnSizing);this.props.onChange({rows:rows,columns:columns,answers:answers,headers:headers});},this.serialize=()=>{const json=_.pick(this.props,"headers","rows","columns");return _.extend({},json,{answers:_.map(this.props.answers,_.clone)})};}}TableEditor.propTypes={rows:PropTypes.number,columns:PropTypes.number,headers:PropTypes.arrayOf(PropTypes.string),answers:PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string))};TableEditor.widgetName="table";TableEditor.defaultProps=tableLogic.defaultWidgetOptions;
1750
+ const KA_VIDEO_URL=/khanacademy\.org\/.*\/v\/(.*)$/;function getSlugFromUrl(url){const match=KA_VIDEO_URL.exec(url);if(match){return match[1]}return url}function VideoSettings(props){const[inputValue,setInputValue]=React.useState(props.location);function handleUrlChange(url){props.onChange({location:getSlugFromUrl(url)});}return jsxRuntimeExports.jsx(LabeledField,{label:"KA Video Slug",description:"KA video URLs will be converted to just the slug.",field:jsxRuntimeExports.jsx(TextArea,{value:inputValue,onChange:setInputValue,onBlur:e=>handleUrlChange(e.target.value),autoResize:true})})}
1747
1751
 
1748
- const{InfoTip}=components;const KA_VIDEO_URL=/khanacademy\.org\/.*\/v\/(.*)$/;function getSlugFromUrl(url){const match=KA_VIDEO_URL.exec(url);if(match){return match[1]}return url}class VideoEditor extends React.Component{render(){return jsxRuntimeExports.jsx("div",{children:jsxRuntimeExports.jsxs("label",{children:["KA Video Slug:"," ",jsxRuntimeExports.jsx(BlurInput,{value:this.props.location,style:{width:290},onChange:this._handleUrlChange}),jsxRuntimeExports.jsx(InfoTip,{children:"KA video URLs will be converted to just the slug."})]})})}constructor(...args){super(...args),this._handleUrlChange=url=>{this.props.onChange({location:getSlugFromUrl(url)});},this.serialize=()=>{return EditorJsonify.serialize.call(this)};}}VideoEditor.propTypes={location:PropTypes.string,onChange:PropTypes.func};VideoEditor.widgetName="video";VideoEditor.defaultProps=videoLogic.defaultWidgetOptions;
1752
+ class VideoEditor extends React.Component{render(){return jsxRuntimeExports.jsx(VideoSettings,{...this.props})}constructor(...args){super(...args),this.serialize=()=>{return {location:this.props.location,static:this.props.static}};}}VideoEditor.widgetName="video";VideoEditor.defaultProps=videoLogic.defaultWidgetOptions;
1749
1753
 
1750
1754
  var AllEditors = [CategorizerEditor,CSProgramEditor,DefinitionEditor,DropdownEditor,ExplanationEditor,ExpressionEditor,FreeResponseEditor,GradedGroupEditor,GradedGroupSetEditor,GrapherEditor,GroupEditor,IframeEditor,ImageEditor,InputNumberEditor,InteractionEditor,InteractiveGraphEditor,LabelImageEditor,MatcherEditor,MatrixEditor,MeasurerEditor,MoleculeWidgetEditor,NumberLineEditor,NumericInputEditor,OrdererEditor,PassageEditor,PassageRefEditor,PassageRefTargetEditor,PhetSimulationEditor,PlotterEditor,PythonProgramEditor,SorterEditor,TableEditor,VideoEditor,RadioEditor,DeprecatedStandinEditor];
1751
1755