@khanacademy/perseus-editor 27.6.1 → 28.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/article-editor.d.ts +2 -1
- package/dist/diffs/article-diff.d.ts +6 -1
- package/dist/diffs/item-diff.d.ts +6 -1
- package/dist/editor-page.d.ts +2 -1
- package/dist/es/index.js +16 -16
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +15 -15
- package/dist/index.js.map +1 -1
- package/dist/widgets/image-editor/image-settings.d.ts +13 -0
- package/package.json +10 -10
package/dist/article-editor.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* multiple (Renderer) sections concatenated together.
|
|
4
4
|
*/
|
|
5
5
|
import * as React from "react";
|
|
6
|
-
import type { APIOptions, Changeable, ImageUploader } from "@khanacademy/perseus";
|
|
6
|
+
import type { APIOptions, Changeable, ImageUploader, PerseusDependenciesV2 } from "@khanacademy/perseus";
|
|
7
7
|
type RendererProps = {
|
|
8
8
|
content?: string;
|
|
9
9
|
widgets?: any;
|
|
@@ -20,6 +20,7 @@ type DefaultProps = {
|
|
|
20
20
|
};
|
|
21
21
|
type Props = DefaultProps & {
|
|
22
22
|
apiOptions?: APIOptions;
|
|
23
|
+
dependencies: PerseusDependenciesV2;
|
|
23
24
|
imageUploader?: ImageUploader;
|
|
24
25
|
previewURL: string;
|
|
25
26
|
} & Changeable.ChangeableProps;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A side by side diff view for Perseus articles.
|
|
3
3
|
*/
|
|
4
|
+
import { type PerseusDependenciesV2 } from "@khanacademy/perseus";
|
|
4
5
|
import * as React from "react";
|
|
5
|
-
|
|
6
|
+
interface Props {
|
|
7
|
+
after: any;
|
|
8
|
+
before: any;
|
|
9
|
+
dependencies: PerseusDependenciesV2;
|
|
10
|
+
}
|
|
6
11
|
type State = any;
|
|
7
12
|
declare class ArticleDiff extends React.Component<Props, State> {
|
|
8
13
|
static propTypes: {
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
* A side by side diff view for Perseus exercise items
|
|
3
3
|
* in the standard layout.
|
|
4
4
|
*/
|
|
5
|
+
import { type PerseusDependenciesV2 } from "@khanacademy/perseus";
|
|
5
6
|
import * as React from "react";
|
|
6
|
-
|
|
7
|
+
interface Props {
|
|
8
|
+
after: any;
|
|
9
|
+
before: any;
|
|
10
|
+
dependencies: PerseusDependenciesV2;
|
|
11
|
+
}
|
|
7
12
|
declare class ItemDiff extends React.Component<Props> {
|
|
8
13
|
static propTypes: {
|
|
9
14
|
after: any;
|
package/dist/editor-page.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import CombinedHintsEditor from "./hint-editor";
|
|
3
3
|
import ItemEditor from "./item-editor";
|
|
4
4
|
import type { Issue } from "./issues-panel";
|
|
5
|
-
import type { APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, ImageUploader } from "@khanacademy/perseus";
|
|
5
|
+
import type { APIOptions, APIOptionsWithDefaults, ChangeHandler, DeviceType, ImageUploader, PerseusDependenciesV2 } from "@khanacademy/perseus";
|
|
6
6
|
import type { Hint, PerseusAnswerArea, PerseusItem, PerseusRenderer } from "@khanacademy/perseus-core";
|
|
7
7
|
type Props = {
|
|
8
8
|
/** Additional templates that the host application would like to display
|
|
@@ -12,6 +12,7 @@ type Props = {
|
|
|
12
12
|
apiOptions?: APIOptions;
|
|
13
13
|
answerArea?: PerseusAnswerArea | null;
|
|
14
14
|
contentPaths?: ReadonlyArray<string>;
|
|
15
|
+
dependencies: PerseusDependenciesV2;
|
|
15
16
|
/** "Power user" mode. Shows the raw JSON of the question. */
|
|
16
17
|
developerMode: boolean;
|
|
17
18
|
hints?: ReadonlyArray<Hint>;
|
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, { useId, createElement, useState, useRef, useEffect } from 'react';
|
|
4
|
-
import { components, Widgets, iconTrash, excludeDenylistKeys, PerseusMarkdown, Util, preprocessTex, Log, ApiOptions, ClassNames, usePerseusI18n, UserInputManager, Renderer, Categorizer as Categorizer$1, Changeable, EditorJsonify,
|
|
4
|
+
import { components, Widgets, iconTrash, excludeDenylistKeys, PerseusMarkdown, Util, preprocessTex, Log, ApiOptions, Dependencies, 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, makeSafeUrl, PlotterWidget, TableWidget, widgets } from '@khanacademy/perseus';
|
|
5
5
|
export { widgets } from '@khanacademy/perseus';
|
|
6
6
|
import { CoreWidgetRegistry, applyDefaultsToWidget, PerseusError, Errors, ItemExtras, categorizerLogic, csProgramLogic, definitionLogic, dropdownLogic, explanationLogic, expressionLogic, deriveExtraKeys, PerseusExpressionAnswerFormConsidered, freeResponseLogic, gradedGroupLogic, gradedGroupSetLogic, grapherLogic, GrapherUtil as GrapherUtil$1, groupLogic, iframeLogic, isFeatureOn, imageLogic, inputNumberLogic, interactionLogic, lockedFigureColors, lockedFigureFillStyles, interactiveGraphLogic, labelImageLogic, matcherLogic, matrixLogic, getMatrixSize, measurerLogic, numberLineLogic, numericInputLogic, ordererLogic, passageLogic, passageRefLogic, passageRefTargetLogic, phetSimulationLogic, plotterLogic, plotterPlotTypes, pythonProgramLogic, radioLogic, deriveNumCorrect, sorterLogic, tableLogic, videoLogic } from '@khanacademy/perseus-core';
|
|
7
7
|
import _ from 'underscore';
|
|
@@ -61,7 +61,7 @@ import xIcon from '@phosphor-icons/core/regular/x.svg';
|
|
|
61
61
|
import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
|
|
62
62
|
import minusCircleIcon from '@phosphor-icons/core/bold/minus-circle-bold.svg';
|
|
63
63
|
|
|
64
|
-
const libName="@khanacademy/perseus-editor";const libVersion="
|
|
64
|
+
const libName="@khanacademy/perseus-editor";const libVersion="28.0.0";addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
65
65
|
|
|
66
66
|
var jsxRuntime = {exports: {}};
|
|
67
67
|
|
|
@@ -1435,7 +1435,7 @@ let nextIframeID=0;const requestIframeData={};const updateIframeHeight={};window
|
|
|
1435
1435
|
|
|
1436
1436
|
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};
|
|
1437
1437
|
|
|
1438
|
-
const{HUD: HUD$1,InlineIcon: InlineIcon$5}=components;class ArticleEditor extends React.Component{componentDidMount(){this._updatePreviewFrames();}componentDidUpdate(){this._updatePreviewFrames();}_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(){return Array.isArray(this.props.json)?this.props.json:[this.props.json]}_renderEditor(){const{imageUploader,sectionImageUploadGenerator}=this.props;const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true};const sections=this._sections();return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[sections.map((section,i)=>{return [jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[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:iconPlus,onClick:()=>{this._handleAddSectionAfter(i);},title:"Add a new section after this one"}),i+1<sections.length&&jsxRuntimeExports.jsx(SectionControlButton,{icon:iconCircleArrowDown,onClick:()=>{this._handleMoveSectionLater(i);},title:"Move this section down"}),i>0&&jsxRuntimeExports.jsx(SectionControlButton,{icon:iconCircleArrowUp,onClick:()=>{this._handleMoveSectionEarlier(i);},title:"Move this section up"}),jsxRuntimeExports.jsx(SectionControlButton,{icon:iconTrash,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(),this._renderLinterHUD()]})}_renderAddSection(){return jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsxs("a",{href:"#",className:"simple-button orange",onClick:()=>{this._handleAddSectionAfter(this._sections().length-1);},children:[jsxRuntimeExports.jsx(InlineIcon$5,{...iconPlus})," 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(){return 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})]})]})}constructor(...args){super(...args),this.state={highlightLint:true},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};
|
|
1438
|
+
const{HUD: HUD$1,InlineIcon: InlineIcon$5}=components;class ArticleEditor extends React.Component{componentDidMount(){this._updatePreviewFrames();}componentDidUpdate(){this._updatePreviewFrames();}_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(){return Array.isArray(this.props.json)?this.props.json:[this.props.json]}_renderEditor(){const{imageUploader,sectionImageUploadGenerator}=this.props;const apiOptions={...ApiOptions.defaults,...this.props.apiOptions,showAlignmentOptions:true,isArticle:true};const sections=this._sections();return jsxRuntimeExports.jsxs("div",{className:"perseus-editor-table",children:[sections.map((section,i)=>{return [jsxRuntimeExports.jsxs("div",{className:"perseus-editor-row",children:[jsxRuntimeExports.jsxs("div",{className:"perseus-editor-left-cell",children:[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:iconPlus,onClick:()=>{this._handleAddSectionAfter(i);},title:"Add a new section after this one"}),i+1<sections.length&&jsxRuntimeExports.jsx(SectionControlButton,{icon:iconCircleArrowDown,onClick:()=>{this._handleMoveSectionLater(i);},title:"Move this section down"}),i>0&&jsxRuntimeExports.jsx(SectionControlButton,{icon:iconCircleArrowUp,onClick:()=>{this._handleMoveSectionEarlier(i);},title:"Move this section up"}),jsxRuntimeExports.jsx(SectionControlButton,{icon:iconTrash,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(),this._renderLinterHUD()]})}_renderAddSection(){return jsxRuntimeExports.jsx("div",{className:"perseus-editor-row",children:jsxRuntimeExports.jsx("div",{className:"perseus-editor-left-cell",children:jsxRuntimeExports.jsxs("a",{href:"#",className:"simple-button orange",onClick:()=>{this._handleAddSectionAfter(this._sections().length-1);},children:[jsxRuntimeExports.jsx(InlineIcon$5,{...iconPlus})," 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(){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})]})]})})}constructor(...args){super(...args),this.state={highlightLint:true},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};
|
|
1439
1439
|
|
|
1440
1440
|
const{ButtonGroup: ButtonGroup$8,InlineIcon: InlineIcon$4}=components;const ViewportResizer=props=>{const phoneButtonContents=jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsx(InlineIcon$4,{...iconMobilePhone})," Phone"]});const tabletButtonContents=jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsx(InlineIcon$4,{...iconTablet})," Tablet"]});const desktopButtonContents=jsxRuntimeExports.jsxs("span",{children:[jsxRuntimeExports.jsx(InlineIcon$4,{...iconDesktop})," Desktop"]});return jsxRuntimeExports.jsxs("span",{className:"viewport-resizer",children:["Viewport:"," ",jsxRuntimeExports.jsx(ButtonGroup$8,{value:props.deviceType,allowEmpty:false,buttons:[{value:devices.PHONE,content:phoneButtonContents},{value:devices.TABLET,content:tabletButtonContents},{value:devices.DESKTOP,content:desktopButtonContents}],onChange:props.onViewportSizeChanged})]})};
|
|
1441
1441
|
|
|
@@ -1453,11 +1453,11 @@ const{SvgImage: SvgImage$2}=components;const indentationFromDepth=function(depth
|
|
|
1453
1453
|
|
|
1454
1454
|
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};
|
|
1455
1455
|
|
|
1456
|
-
const rendererProps=PropTypes.shape({content:PropTypes.string,images:PropTypes.objectOf(PropTypes.any),widgets:PropTypes.objectOf(PropTypes.any)});class ArticleDiff extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState(ArticleDiff._stateFromProps(nextProps));}render(){const{before,after}=this.state;const sectionCount=Math.max(before.length,after.length);const sections=_.times(sectionCount,n=>jsxRuntimeExports.jsx(RendererDiff,{before:n<before.length?before[n]:undefined,after:n<after.length?after[n]:undefined,title:`Section ${n+1}`,showAlignmentOptions:true,showSeparator:n<sectionCount-1},n));return jsxRuntimeExports.jsx("div",{className:"framework-perseus",children:sections})}constructor(...args){super(...args),this.state=ArticleDiff._stateFromProps(this.props);}}ArticleDiff.propTypes={after:PropTypes.oneOfType([rendererProps,PropTypes.arrayOf(rendererProps)]).isRequired,before:PropTypes.oneOfType([rendererProps,PropTypes.arrayOf(rendererProps)]).isRequired};ArticleDiff._stateFromProps=props=>{const{before,after}=props;return {before:Array.isArray(before)?before:[before],after:Array.isArray(after)?after:[after]}};
|
|
1456
|
+
const rendererProps=PropTypes.shape({content:PropTypes.string,images:PropTypes.objectOf(PropTypes.any),widgets:PropTypes.objectOf(PropTypes.any)});class ArticleDiff extends React.Component{UNSAFE_componentWillReceiveProps(nextProps){this.setState(ArticleDiff._stateFromProps(nextProps));}render(){const{before,after}=this.state;const sectionCount=Math.max(before.length,after.length);const sections=_.times(sectionCount,n=>jsxRuntimeExports.jsx(RendererDiff,{before:n<before.length?before[n]:undefined,after:n<after.length?after[n]:undefined,title:`Section ${n+1}`,showAlignmentOptions:true,showSeparator:n<sectionCount-1},n));return jsxRuntimeExports.jsx(Dependencies.DependenciesContext.Provider,{value:this.props.dependencies,children:jsxRuntimeExports.jsx("div",{className:"framework-perseus",children:sections})})}constructor(...args){super(...args),this.state=ArticleDiff._stateFromProps(this.props);}}ArticleDiff.propTypes={after:PropTypes.oneOfType([rendererProps,PropTypes.arrayOf(rendererProps)]).isRequired,before:PropTypes.oneOfType([rendererProps,PropTypes.arrayOf(rendererProps)]).isRequired};ArticleDiff._stateFromProps=props=>{const{before,after}=props;return {before:Array.isArray(before)?before:[before],after:Array.isArray(after)?after:[after]}};
|
|
1457
1457
|
|
|
1458
|
-
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.jsxs("div",{className:"framework-perseus",children:[question,extras,hints&&jsxRuntimeExports.jsx("div",{className:"diff-separator"}),hints]})}}ItemDiff.propTypes={after:itemProps.isRequired,before:itemProps.isRequired};
|
|
1458
|
+
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};
|
|
1459
1459
|
|
|
1460
|
-
const{InfoTip: InfoTip$
|
|
1460
|
+
const{InfoTip: InfoTip$p,InlineIcon: InlineIcon$3}=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$3,{...iconCircleArrowDown})})," ",jsxRuntimeExports.jsx("button",{type:"button",className:this.props.isFirst?"hidden":"",onClick:_.partial(this.props.onMove,-1),children:jsxRuntimeExports.jsx(InlineIcon$3,{...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$3,{...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 hintElems=_.map(hints,function(hint,i){return 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",onClick:this.addHint,children:[jsxRuntimeExports.jsx(InlineIcon$3,{...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};
|
|
1461
1461
|
|
|
1462
1462
|
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$Q.container,containerStyle],headerStyle:[styles$Q.accordionHeader,headerStyle],header:header,children:jsxRuntimeExports.jsx(View,{style:[styles$Q.accordionPanel,panelStyle],children:children})})})};const styles$Q=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}});
|
|
1463
1463
|
|
|
@@ -1465,13 +1465,13 @@ const IssueDetails=({issue})=>{const[expanded,setExpanded]=React.useState(false)
|
|
|
1465
1465
|
|
|
1466
1466
|
const IssuesPanel=({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;const togglePanel=()=>{if(hasWarnings){setShowPanel(!showPanel);}};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:togglePanel,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.jsx("div",{className:"perseus-widget-editor-content",children:issues.map(issue=>jsxRuntimeExports.jsx(IssueDetails,{issue:issue},issue.id))})})]})};
|
|
1467
1467
|
|
|
1468
|
-
const{InfoTip: InfoTip$
|
|
1468
|
+
const{InfoTip: InfoTip$o}=components;class ItemExtrasEditor extends React.Component{shouldShowFinancialCalculatorOptions(){return this.props.financialCalculatorMonthlyPayment||this.props.financialCalculatorTotalAmount||this.props.financialCalculatorTimeToPayOff}render(){return jsxRuntimeExports.jsx("div",{className:"perseus-answer-editor",children:jsxRuntimeExports.jsxs("div",{className:"perseus-answer-options",children:[jsxRuntimeExports.jsx(ItemExtraCheckbox,{label:"Show calculator",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",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",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",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",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",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",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$P.checkbox,props.indent?styles$P.indented:undefined],children:jsxRuntimeExports.jsx(Checkbox$1,{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$P=StyleSheet.create({indented:{marginInlineStart:spacing.large_24}});
|
|
1469
1469
|
|
|
1470
1470
|
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)=>({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:"low",message:message})};
|
|
1471
1471
|
|
|
1472
1472
|
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)})??[]]}}render(){const isMobile=this.props.deviceType==="phone"||this.props.deviceType==="tablet";return 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,{issues:this.state.issues}),jsxRuntimeExports.jsx("div",{className:"pod-title",children:"Question"}),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,...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:{}};
|
|
1473
1473
|
|
|
1474
|
-
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 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.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,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})}),(!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:()=>{}};
|
|
1474
|
+
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 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,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})}),(!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:()=>{}};
|
|
1475
1475
|
|
|
1476
1476
|
function ContentPreview({question,apiOptions,seamless,linterContext,legacyPerseusLint,previewDevice}){const i18n=usePerseusI18n();const isMobile=previewDevice!=="desktop";const className=isMobile?"perseus-mobile":"";return jsxRuntimeExports.jsx(View,{className:`framework-perseus ${className}`,style:[styles$O.container,!seamless?styles$O.gutter:undefined],children:jsxRuntimeExports.jsx(StatefulKeypadContextProvider,{children:jsxRuntimeExports.jsx(KeypadContext.Consumer,{children:({setKeypadActive,keypadElement,setKeypadElement})=>jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(UserInputManager,{widgets:question?.widgets||{},problemNum:0,children:({userInput,handleUserInput,initializeUserInput})=>jsxRuntimeExports.jsx(Renderer,{strings:i18n.strings,apiOptions:{...apiOptions,isMobile},keypadElement:keypadElement,linterContext:linterContext,legacyPerseusLint:legacyPerseusLint,userInput:userInput,handleUserInput:handleUserInput,initializeUserInput:initializeUserInput,...question})}),jsxRuntimeExports.jsx(MobileKeypad,{onAnalyticsEvent:()=>Promise.resolve(),onDismiss:()=>setKeypadActive(false),onElementMounted:setKeypadElement})]})})})})}const styles$O=StyleSheet.create({container:{padding:spacing.xxxSmall_4,containerType:"inline-size",containerName:"perseus-root"},gutter:{marginRight:lintGutterWidth}});
|
|
1477
1477
|
|
|
@@ -1479,18 +1479,18 @@ const{TextListEditor: TextListEditor$4}=components;const Categorizer=Categorizer
|
|
|
1479
1479
|
|
|
1480
1480
|
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};}}
|
|
1481
1481
|
|
|
1482
|
-
const{InfoTip: InfoTip$
|
|
1482
|
+
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;
|
|
1483
1483
|
|
|
1484
1484
|
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;
|
|
1485
1485
|
|
|
1486
1486
|
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";
|
|
1487
1487
|
|
|
1488
|
-
const{InfoTip: InfoTip$
|
|
1488
|
+
const{InfoTip: InfoTip$m,InlineIcon: InlineIcon$2}=components;class DropdownEditor extends React.Component{render(){const dropdownGroupName=_.uniqueId("perseus_dropdown_");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(function(choice,i){const checkedClass=choice.correct?"correct":"incorrect";return jsxRuntimeExports.jsx("li",{children:jsxRuntimeExports.jsxs("div",{children:[jsxRuntimeExports.jsx("input",{ref:"radio"+i,type:"radio",name:dropdownGroupName,checked:choice.correct?"checked":"",onChange:this.onCorrectChange.bind(this,i),value:i}),jsxRuntimeExports.jsx("input",{type:"text",ref:"editor"+i,onChange:this.onContentChange.bind(this,i),className:checkedClass,value:choice.content}),jsxRuntimeExports.jsx("a",{href:"#",className:"simple-button orange","aria-label":"Delete choice",onClick:this.removeChoice.bind(this,i),children:jsxRuntimeExports.jsx("span",{className:"remove-choice",children:jsxRuntimeExports.jsx(InlineIcon$2,{...iconTrash})})})]})},""+i)},this)}),jsxRuntimeExports.jsx("div",{className:"add-choice-container",children:jsxRuntimeExports.jsxs("a",{href:"#",className:"simple-button orange",onClick:this.addChoice,children:[jsxRuntimeExports.jsx(InlineIcon$2,{...iconPlus})," 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,e)=>{const choices=this.props.choices.slice();const choice=_.clone(choices[choiceIndex]);choice.content=e.target.value;choices[choiceIndex]=choice;this.props.onChange({choices:choices});},this.addChoice=e=>{e.preventDefault();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,e)=>{e.preventDefault();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;
|
|
1489
1489
|
|
|
1490
1490
|
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;
|
|
1491
1491
|
|
|
1492
|
-
const{ButtonGroup: ButtonGroup$7,InfoTip: InfoTip$
|
|
1493
|
-
" 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$N.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:css(styles$N.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$N.paddedY,styles$N.paddedX),children:jsxRuntimeExports.jsx(Checkbox$1,{label:jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:["Answer expression must have the same form.",jsxRuntimeExports.jsx(InfoTip$
|
|
1492
|
+
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$N.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$N.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$N.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$N.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$N.paddedY),children:[jsxRuntimeExports.jsx(HeadingXSmall,{children:"Button Sets"}),buttonSetChoices]}),jsxRuntimeExports.jsx(HeadingSmall,{children:"Answers"}),jsxRuntimeExports.jsx(Caption,{style:styles$N.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" +
|
|
1493
|
+
" 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$N.deleteButton,children:"Delete"});return jsxRuntimeExports.jsxs("div",{className:css(styles$N.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$N.paddedY,styles$N.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$N.paddedY,styles$N.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$N.buttonRow,styles$N.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$N=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$N.answerStatusWrong,correct:styles$N.answerStatusCorrect,ungraded:styles$N.answerStatusUngraded};
|
|
1494
1494
|
|
|
1495
1495
|
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$M.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$M.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$M.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$M.labeledInputField}}),jsxRuntimeExports.jsxs(View,{children:[jsxRuntimeExports.jsx(HeadingSmall,{children:"Scoring criteria"}),jsxRuntimeExports.jsx(View,{style:styles$M.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$M.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$M.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,children:"Delete"})})]})};const styles$M=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}});
|
|
1496
1496
|
|
|
@@ -1498,9 +1498,9 @@ const{InlineIcon: InlineIcon$1,TextInput: TextInput$5}=components;class GradedGr
|
|
|
1498
1498
|
|
|
1499
1499
|
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)];
|
|
1500
1500
|
|
|
1501
|
-
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};
|
|
1501
|
+
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};
|
|
1502
1502
|
|
|
1503
|
-
const{InfoTip: InfoTip$
|
|
1503
|
+
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,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(){}};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;
|
|
1504
1504
|
|
|
1505
1505
|
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;
|
|
1506
1506
|
|
|
@@ -1510,9 +1510,9 @@ const AutoResizingTextArea=props=>{const textAreaRef=React.useRef(null);React.us
|
|
|
1510
1510
|
|
|
1511
1511
|
var styles$K = {"dimensionsContainer":"perseus_4qo24hC2"};
|
|
1512
1512
|
|
|
1513
|
-
const{SvgImage: SvgImage$1}=components;function ImageSettings({alt,backgroundImage,apiOptions,caption,longDescription,title,onChange}){const imageUpgradeFF=isFeatureOn({apiOptions},"image-widget-upgrade");if(!backgroundImage.url){return null}const dimensions=`${backgroundImage.width} x ${backgroundImage.height}`;const dimensionString=backgroundImage.width&&backgroundImage.height?dimensions:"unknown";return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment,{children:[jsxRuntimeExports.jsx(LabeledField,{label:"Preview
|
|
1513
|
+
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,longDescription,title,onChange}){const imageUpgradeFF=isFeatureOn({apiOptions},"image-widget-upgrade");const[altFieldError,setAltFieldError]=React.useState(null);if(!backgroundImage.url){return null}const dimensions=`${backgroundImage.width} x ${backgroundImage.height}`;const dimensionString=backgroundImage.width&&backgroundImage.height?dimensions:"unknown";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"}`}),styles:wbFieldStyles}),jsxRuntimeExports.jsxs("div",{className:styles$K.dimensionsContainer,children:[jsxRuntimeExports.jsx(HeadingXSmall,{style:{padding:0,marginInlineEnd:sizing.size_080,color:"var(--wb-semanticColor-core-foreground-neutral-strong)"},children:"Dimensions:"}),dimensionString]}),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}),errorMessage:altFieldError,styles:wbFieldStylesWithDescription}),imageUpgradeFF&&jsxRuntimeExports.jsx(LabeledField,{label:"Long description",field:jsxRuntimeExports.jsx(AutoResizingTextArea,{value:longDescription??"",onChange:value=>onChange({longDescription:value})}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Title",field:jsxRuntimeExports.jsx(AutoResizingTextArea,{value:title??"",onChange:value=>onChange({title:value})}),styles:wbFieldStyles}),jsxRuntimeExports.jsx(LabeledField,{label:"Caption",field:jsxRuntimeExports.jsx(AutoResizingTextArea,{value:caption??"",onChange:value=>onChange({caption:value})}),styles:wbFieldStyles})]})}const wbFieldStyles={root:{marginBlockEnd:sizing.size_080},label:{fontWeight:"bold",paddingBlockEnd:sizing.size_040}};const wbFieldStylesWithDescription={...wbFieldStyles,label:{...wbFieldStyles.label,paddingBlockEnd:0},description:{paddingBlockStart:0,paddingBlockEnd:sizing.size_040}};
|
|
1514
1514
|
|
|
1515
|
-
const
|
|
1515
|
+
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})}
|
|
1516
1516
|
|
|
1517
1517
|
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;
|
|
1518
1518
|
|