From 9dd07f53899858d273fac920af0321209ed0fe10 Mon Sep 17 00:00:00 2001 From: Yannis Barlas <yannisbarlas@gmail.com> Date: Thu, 11 Aug 2022 18:45:27 +0300 Subject: [PATCH] fix(services): add pure readonly state to hhmi services --- editors/demo/src/HHMI/HHMI.js | 94 +++++++++++++++++-- editors/demo/src/HHMI/layout/HhmiLayout.js | 5 +- wax-prosemirror-core/src/Wax.js | 1 + wax-prosemirror-services/package.json | 1 + .../components/EditorComponent.js | 7 +- .../FillTheGapContainerComponent.js | 6 +- .../components/DropDownComponent.js | 10 +- .../components/MatchingContainerComponent.js | 82 +++++++++------- .../components/MatchingOptionComponent.js | 21 +++-- .../components/AnswerComponent.js | 3 +- .../components/YesNoSwitch.js | 16 +++- .../MultipleDropDownContainerComponent.js | 5 +- 12 files changed, 176 insertions(+), 75 deletions(-) diff --git a/editors/demo/src/HHMI/HHMI.js b/editors/demo/src/HHMI/HHMI.js index f161b02fa..cc2adbefa 100644 --- a/editors/demo/src/HHMI/HHMI.js +++ b/editors/demo/src/HHMI/HHMI.js @@ -1,5 +1,5 @@ import React, { useState, useRef } from 'react'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { Wax } from 'wax-prosemirror-core'; @@ -16,16 +16,60 @@ const renderImage = file => { }); }; +const NormalButton = styled.button` + left: 600px; + position: absolute; + top: 16px; + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${props => + props.isActive && + css` + background-color: gray; + color: white; + `} +`; + const ReadOnlyButton = styled.button` + left: 670px; + position: absolute; + top: 16px; + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${props => + props.isActive && + css` + background-color: gray; + color: white; + `} +`; + +const TestModeButton = styled.button` + left: 760px; position: absolute; - left: 600px; top: 16px; + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${props => + props.isActive && + css` + background-color: gray; + color: white; + `} `; const SubmitButton = styled.button` + left: 850px; position: absolute; - left: 700px; top: 16px; + + /* stylelint-disable-next-line order/properties-alphabetical-order */ + ${props => + props.isActive && + css` + background-color: gray; + color: white; + `} `; const initialContent = `<p class="paragraph"></p> @@ -55,32 +99,64 @@ const initialContent = `<p class="paragraph"></p> </div>`; const Hhmi = () => { - const [submited, isSubmited] = useState(false); + const [submitted, isSubmitted] = useState(false); const [readOnly, isReadOnly] = useState(false); + const [testMode, isTestMode] = useState(false); const [content, setContent] = useState(initialContent); + const normalQuestions = () => { + isReadOnly(false); + isTestMode(false); + isSubmitted(false); + setContent(editorRef.current.getContent()); + }; + const readOnlyQuestions = () => { + isReadOnly(true); + isTestMode(false); + isSubmitted(false); setContent(editorRef.current.getContent()); + }; + + const testModeQuestions = () => { isReadOnly(true); + isTestMode(true); + isSubmitted(false); + setContent(editorRef.current.getContent()); }; const submitQuestions = () => { - setContent(editorRef.current.getContent()); - isSubmited(true); isReadOnly(true); + isTestMode(false); + isSubmitted(true); + setContent(editorRef.current.getContent()); }; const editorRef = useRef(); return ( <> - <ReadOnlyButton onClick={readOnlyQuestions}>Read Only</ReadOnlyButton> - <SubmitButton onClick={submitQuestions}>Submit</SubmitButton> + <NormalButton isActive={!readOnly} onClick={normalQuestions}> + Normal + </NormalButton> + <ReadOnlyButton + isActive={readOnly && !submitted && !testMode} + onClick={readOnlyQuestions} + > + Read Only + </ReadOnlyButton> + <TestModeButton isActive={testMode} onClick={testModeQuestions}> + Test Mode + </TestModeButton> + <SubmitButton isActive={submitted} onClick={submitQuestions}> + Submit + </SubmitButton> + <Wax config={config} autoFocus ref={editorRef} - customValues={{ showFeedBack: submited }} + customValues={{ showFeedBack: submitted, testMode }} fileUpload={file => renderImage(file)} value={content} readonly={readOnly} diff --git a/editors/demo/src/HHMI/layout/HhmiLayout.js b/editors/demo/src/HHMI/layout/HhmiLayout.js index 436f33949..4179a73e5 100644 --- a/editors/demo/src/HHMI/layout/HhmiLayout.js +++ b/editors/demo/src/HHMI/layout/HhmiLayout.js @@ -59,22 +59,23 @@ const EditorArea = styled.div` `; const WaxSurfaceScroll = styled.div` - padding: 25px 25% 0 25%; box-sizing: border-box; display: flex; height: 100%; overflow-y: auto; + padding: 25px 25% 0 25%; position: relative; width: 100%; /* PM styles for main content*/ + /* stylelint-disable-next-line order/properties-alphabetical-order */ ${EditorElements}; `; const EditorContainer = styled.div` height: 100%; - width: 100%; position: relative; + width: 100%; .ProseMirror { box-shadow: 0 0 8px #ecedf1; diff --git a/wax-prosemirror-core/src/Wax.js b/wax-prosemirror-core/src/Wax.js index a06ea9def..97b73c65c 100644 --- a/wax-prosemirror-core/src/Wax.js +++ b/wax-prosemirror-core/src/Wax.js @@ -96,6 +96,7 @@ const Wax = forwardRef((props, ref) => { Wax.defaultProps = { config: { SchemaService: DefaultSchema, services: [] }, + customValues: {}, }; export default Wax; diff --git a/wax-prosemirror-services/package.json b/wax-prosemirror-services/package.json index dbdbf9637..ad1a4b739 100644 --- a/wax-prosemirror-services/package.json +++ b/wax-prosemirror-services/package.json @@ -27,6 +27,7 @@ "prosemirror-transform": "1.3.4", "prosemirror-view": "1.23.7", "rc-switch": "^3.2.2", + "react-dropdown": "^1.6.2", "styled-components": "^5.3.0", "use-deep-compare-effect": "^1.3.1", "uuid": "^7.0.3", diff --git a/wax-prosemirror-services/src/FillTheGapQuestionService/components/EditorComponent.js b/wax-prosemirror-services/src/FillTheGapQuestionService/components/EditorComponent.js index 957d773ca..40f5efe55 100644 --- a/wax-prosemirror-services/src/FillTheGapQuestionService/components/EditorComponent.js +++ b/wax-prosemirror-services/src/FillTheGapQuestionService/components/EditorComponent.js @@ -1,4 +1,5 @@ /* eslint-disable react/prop-types */ +/* stylelint-disable declaration-no-important */ import React, { useContext, useRef, useEffect } from 'react'; import styled from 'styled-components'; @@ -147,9 +148,9 @@ const EditorComponent = ({ node, view, getPos }) => { if (!tr.getMeta('fromOutside')) { const outerTr = view.state.tr; const offsetMap = StepMap.offset(getPos() + 1); - for (let i = 0; i < transactions.length; i++) { + for (let i = 0; i < transactions.length; i += 1) { const { steps } = transactions[i]; - for (let j = 0; j < steps.length; j++) + for (let j = 0; j < steps.length; j += 1) outerTr.step(steps[j].map(offsetMap)); } if (outerTr.docChanged) @@ -159,7 +160,7 @@ const EditorComponent = ({ node, view, getPos }) => { return ( <> - {isEditable ? ( + {isEditable || (!isEditable && !main.props.customValues.testMode) ? ( <EditorWrapper> <div ref={editorRef} /> </EditorWrapper> diff --git a/wax-prosemirror-services/src/FillTheGapQuestionService/components/FillTheGapContainerComponent.js b/wax-prosemirror-services/src/FillTheGapQuestionService/components/FillTheGapContainerComponent.js index 6a39e42d9..a1b2defc1 100644 --- a/wax-prosemirror-services/src/FillTheGapQuestionService/components/FillTheGapContainerComponent.js +++ b/wax-prosemirror-services/src/FillTheGapQuestionService/components/FillTheGapContainerComponent.js @@ -11,9 +11,7 @@ const FillTheGapContainer = styled.div` `; const FillTheGapWrapper = styled.div` - margin-bottom: ; margin: 0px 38px 15px 38px; - margin-top: 10px; `; @@ -24,6 +22,7 @@ export default ({ node, view, getPos }) => { } = context; const customProps = main.props.customValues; + const { testMode } = customProps; const isEditable = main.props.editable(editable => { return editable; @@ -36,7 +35,8 @@ export default ({ node, view, getPos }) => { <span>Fill The Gap</span> <FillTheGapContainer className="fill-the-gap"> <ContainerEditor getPos={getPos} node={node} view={view} /> - {!(readOnly && customProps && !customProps.showFeedBack) && ( + + {!testMode && ( <FeedbackComponent getPos={getPos} node={node} diff --git a/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js b/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js index 951a12109..4dfbba335 100644 --- a/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js +++ b/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js @@ -12,11 +12,12 @@ const Wrapper = styled.div` ${ReactDropDownStyles}; `; const DropdownStyled = styled(Dropdown)` - display: inline-flex; cursor: not-allowed; + display: inline-flex; margin-left: auto; opacity: ${props => (props.select ? 1 : 0.4)}; pointer-events: ${props => (props.select ? 'default' : 'none')}; + .Dropdown-control { border: none; padding: 8px 30px 8px 10px; @@ -31,10 +32,11 @@ const DropdownStyled = styled(Dropdown)` } .Dropdown-menu { - width: 102%; + align-items: flex-start; display: flex; flex-direction: column; - align-items: flex-start; + width: 102%; + .Dropdown-option { width: 100%; } @@ -85,7 +87,7 @@ const DropComponent = ({ getPos, node, view }) => { placeholder="Select option" select value={ - selectedOption === 'undedfined' ? 'Select Option' : selectedOption + selectedOption === 'undefined' ? 'Select Option' : selectedOption } /> </Wrapper> diff --git a/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js b/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js index 31b7dcd63..166d1a35d 100644 --- a/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js +++ b/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js @@ -29,10 +29,10 @@ const QuestionWrapper = styled.div` `; const ActionButton = styled.button` - height: 24px; - border: none; background: transparent; + border: none; cursor: pointer; + height: 24px; padding-left: 0; `; @@ -53,27 +53,27 @@ const OptionArea = styled.div` ul { display: flex; - flex-wrap: wrap; flex-direction: row; + flex-wrap: wrap; margin: 0; padding: 0; + li { list-style-type: none; - padding-right: 7px; padding-bottom: 7px; + padding-right: 7px; span { background: #535e76; + border-radius: 12px; color: white; padding: 3px 3px 3px 10px; - border-radius: 12px; - } - buttton { } + svg { fill: white; - width: 16px; height: 16px; + width: 16px; } } } @@ -81,9 +81,11 @@ const OptionArea = styled.div` const AddOption = styled.div` display: flex; + input { border: none; border-bottom: 1px solid black; + &:focus { outline: none; } @@ -93,21 +95,21 @@ const AddOption = styled.div` font-style: italic; } } + button { + background: #fff; border: 1px solid #535e76; - cursor: pointer; color: #535e76; + cursor: pointer; margin-left: 20px; - background: #fff; padding: 4px 8px 4px 8px; + &:hover { + background: #535e76; border: 1px solid #535e76; + color: #fff; cursor: pointer; - color: #535e76; margin-right: 20px; - background: #fff; - background: #535e76; - color: #fff; padding: 4px 8px 4px 8px; } } @@ -136,7 +138,7 @@ export default ({ node, view, getPos }) => { useEffect(() => { const allNodes = getNodes(main); - /*TEMP TO SAVE NODE OPTIONS TODO: SAVE IN CONTEXT OPTIONS*/ + /* TEMP TO SAVE NODE OPTIONS TODO: SAVE IN CONTEXT OPTIONS */ saveInChildOptions(allNodes); if (!addingOption) return; @@ -190,6 +192,7 @@ export default ({ node, view, getPos }) => { singleNode.node.content.content.forEach(parentNodes => { parentNodes.forEach(optionNode => { if (optionNode.type.name === 'matching_option') + /* eslint-disable-next-line no-param-reassign */ optionNode.attrs.options = options; }); }); @@ -204,7 +207,8 @@ export default ({ node, view, getPos }) => { <QuestionWrapper> <ContainerEditor getPos={getPos} node={node} view={view} /> </QuestionWrapper> - {!readOnly && ( + {(!readOnly || + (readOnly && !customProps.testMode && !customProps.showFeedBack)) && ( <CreateOptions> <OptionArea> {options.length > 0 && ( @@ -215,12 +219,14 @@ export default ({ node, view, getPos }) => { <li key={option.value}> <span> {option.label} - <ActionButton - onClick={() => removeOption(option.value)} - type="button" - > - <StyledIconAction name="deleteOutlined" /> - </ActionButton> + {!readOnly && ( + <ActionButton + onClick={() => removeOption(option.value)} + type="button" + > + <StyledIconAction name="deleteOutlined" /> + </ActionButton> + )} </span> </li> ); @@ -228,22 +234,26 @@ export default ({ node, view, getPos }) => { </ul> )} </OptionArea> - <AddOption> - <input - onChange={updateOptionText} - onKeyPress={handleKeyDown} - placeholder="Type an option ..." - ref={addOptionRef} - type="text" - value={optionText} - /> - <button onClick={addOption} type="button"> - Add Option - </button> - </AddOption> + + {!readOnly && ( + <AddOption> + <input + onChange={updateOptionText} + onKeyPress={handleKeyDown} + placeholder="Type an option ..." + ref={addOptionRef} + type="text" + value={optionText} + /> + <button onClick={addOption} type="button"> + Add Option + </button> + </AddOption> + )} </CreateOptions> )} - {!(readOnly && !customProps.showFeedBack) && ( + {(!(readOnly && !customProps.showFeedBack) || + (readOnly && !customProps.testMode && !customProps.showFeedBack)) && ( <FeedbackComponent getPos={getPos} node={node} diff --git a/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js b/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js index 71a30cccf..5bd695e1b 100644 --- a/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js +++ b/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js @@ -1,5 +1,5 @@ /* eslint-disable react/prop-types */ -import React, { useContext, useState } from 'react'; +import React, { useContext } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { TextSelection } from 'prosemirror-state'; import { Fragment } from 'prosemirror-model'; @@ -13,28 +13,28 @@ import ReadOnlyDropDownComponent from './ReadOnlyDropDownComponent'; const Option = styled.div` display: flex; flex-direction: row; - width: 100%; padding-bottom: 10px; + width: 100%; `; const ButtonsContainer = styled.div` - width: 7%; display: flex; flex-direction: column; justify-content: center; + width: 7%; `; const DropDownContainer = styled.div` display: flex; - justify-content: center; flex-direction: column; + justify-content: center; `; const ActionButton = styled.button` - height: 24px; - border: none; background: transparent; + border: none; cursor: pointer; + height: 24px; padding-left: 0; `; @@ -44,9 +44,9 @@ const StyledIconAction = styled(Icon)` `; const AnswerContainer = styled.div` - margin-left: 10px; display: flex; flex-direction: column; + margin-left: 10px; `; const CorrectAnswer = styled.span` span { @@ -72,6 +72,7 @@ export default ({ node, view, getPos }) => { const readOnly = !isEditable; const customProps = main.props.customValues; + const { testMode, showFeedBack } = customProps; const addAnswer = () => { const nodeId = node.attrs.id; @@ -133,15 +134,15 @@ export default ({ node, view, getPos }) => { )} <EditorComponent getPos={getPos} node={node} view={view} /> <DropDownContainer> - {!readOnly && ( + {(!readOnly || (readOnly && !testMode && !showFeedBack)) && ( <DropDownComponent getPos={getPos} node={node} view={view} /> )} - {readOnly && customProps && !customProps.showFeedBack && ( + {readOnly && testMode && !showFeedBack && ( <ReadOnlyDropDownComponent getPos={getPos} node={node} view={view} /> )} - {readOnly && customProps && customProps.showFeedBack && ( + {readOnly && showFeedBack && ( <AnswerContainer> <CorrectAnswer> Correct : {correct && <span>{correct.label} </span>} diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js index c4b4574da..d4a73181b 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js @@ -172,6 +172,7 @@ export default ({ node, view, getPos }) => { }; const readOnly = !isEditable; + const { testMode } = customProps; return ( <Wrapper> @@ -184,7 +185,7 @@ export default ({ node, view, getPos }) => { <QuestionData> <EditorComponent getPos={getPos} node={node} view={view} /> </QuestionData> - {!(readOnly && customProps && !customProps.showFeedBack) && ( + {!testMode && ( <FeedbackComponent getPos={getPos} node={node} diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/YesNoSwitch.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/YesNoSwitch.js index b68f967f5..0b12a6a49 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/YesNoSwitch.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/YesNoSwitch.js @@ -15,6 +15,7 @@ const AnswerContainer = styled.span` const Correct = styled.span` margin-right: 10px; + span { color: #008000; } @@ -22,6 +23,7 @@ const Correct = styled.span` const Answer = styled.span` margin-right: 10px; + span { color: ${props => (props.isCorrect ? ' #008000' : 'red')}; } @@ -29,15 +31,15 @@ const Answer = styled.span` const StyledIconCorrect = styled(Icon)` fill: #008000; - pointer-events: none; height: 24px; + pointer-events: none; width: 24px; `; const StyledIconWrong = styled(Icon)` fill: red; - pointer-events: none; height: 24px; + pointer-events: none; width: 24px; `; const YesNoSwitch = ({ @@ -48,7 +50,9 @@ const YesNoSwitch = ({ checked, checkedAnswerMode, }) => { - if (customProps && customProps.showFeedBack) { + const { testMode, showFeedBack } = customProps; + + if (showFeedBack) { const correct = node.attrs.correct ? 'YES' : 'NO'; const answer = node.attrs.answer ? 'YES' : 'NO'; const isCorrect = node.attrs.correct === node.attrs.answer; @@ -68,10 +72,14 @@ const YesNoSwitch = ({ </AnswerContainer> ); } + return ( <StyledSwitch - checked={isEditable ? checked : checkedAnswerMode} + checked={ + isEditable || (!isEditable && !testMode) ? checked : checkedAnswerMode + } checkedChildren="YES" + disabled={!isEditable && !testMode} label="Correct?" labelPosition="left" onChange={handleChange} diff --git a/wax-prosemirror-services/src/MultipleDropDownService/components/MultipleDropDownContainerComponent.js b/wax-prosemirror-services/src/MultipleDropDownService/components/MultipleDropDownContainerComponent.js index d6725bb7d..acc86907c 100644 --- a/wax-prosemirror-services/src/MultipleDropDownService/components/MultipleDropDownContainerComponent.js +++ b/wax-prosemirror-services/src/MultipleDropDownService/components/MultipleDropDownContainerComponent.js @@ -6,9 +6,7 @@ import ContainerEditor from './ContainerEditor'; import FeedbackComponent from './FeedbackComponent'; const MultipleDropDownpWrapper = styled.div` - margin-bottom: ; margin: 0px 38px 15px 38px; - margin-top: 10px; `; @@ -30,13 +28,14 @@ export default ({ node, view, getPos }) => { }); const readOnly = !isEditable; + const { testMode } = customProps; return ( <MultipleDropDownpWrapper> <span>Multiple Drop Down</span> <MultipleDropDownpContainer className="multiple-drop-down"> <ContainerEditor getPos={getPos} node={node} view={view} /> - {!(readOnly && customProps && !customProps.showFeedBack) && ( + {!testMode && ( <FeedbackComponent getPos={getPos} node={node} -- GitLab