diff --git a/editors/demo/src/HHMI/HHMI.js b/editors/demo/src/HHMI/HHMI.js index c5e19cc8930fdd998a2f7a1b2c5e32fc9ebf55eb..01e244d5ebaf29692e7a266858b1825363398c8d 100644 --- a/editors/demo/src/HHMI/HHMI.js +++ b/editors/demo/src/HHMI/HHMI.js @@ -28,8 +28,7 @@ const SubmitButton = styled.button` top: 16px; `; -const t = `<p class="paragraph"></p> -<div id="1c3b3bc9-8a82-4fae-9f00-5f3a2605d891" class="matching-container" answers="" feedback=""><p class="paragraph"><div class="matching-option" id="5677a6df-7211-481f-b0d7-94565c87bdbd" correct="false" answer="false"></div></p><p class="paragraph"></p></div><p class="paragraph">s</p><div id="d4fa43fc-3a92-4591-a8a4-e6271e42fc323" class="multiple-choice"><div class="multiple-choice-question" id="38de8538-647a-489d-8474-f92d0d256c32"><p class="paragraph">question</p></div><div class="multiple-choice-option" id="debb868e-bbfe-4ba2-bf93-c963153ff791" correct="false" answer="false" feedback="feedback 1"><p class="paragraph">answer 1</p></div><div class="multiple-choice-option" id="810bcf10-4fcb-4d1e-9dab-ce35cbd28527" correct="true" answer="true" feedback="feedback 2"><p class="paragraph">answer 2</p></div></div><div id="d4fa43fc-3a92-4591-a8a4-e6271e42fc02" class="fill-the-gap" feedback="some feedback"><p class="paragraph">first <span id="16ec8f33-db5b-4839-9567-8aa73b776bcf" class="fill-the-gap" anser="">answer1; answer2; answer3</span> second <span id="72f23a71-e774-4834-acba-f357afb6a243" class="fill-the-gap" anser="">answer 4; answer5;</span></p></div>`; +const t = `<p class="paragraph"></p><div id="1c3b3bc9-8a82-4fae-9f00-5f3a2605d891" class="matching-container" options="[{"label":"option 1","key":"d916e258-be52-4bd3-a40f-779beb4f2cf5"},{"label":"option 2","key":"58ed31b1-dc66-46d8-8049-c0e0c582e63e"}]" feedback=""><p class="paragraph"></p><p class="paragraph"><div class="matching-option" id="5677a6df-7211-481f-b0d7-94565c87bdbd" isfirst="true" correct="false" answer="false"></div></p><p class="paragraph"></p></div><p class="paragraph">s</p><div id="d4fa43fc-3a92-4591-a8a4-e6271e42fc323" class="multiple-choice"><div class="multiple-choice-question" id="38de8538-647a-489d-8474-f92d0d256c32"><p class="paragraph">question</p></div><div class="multiple-choice-option" id="debb868e-bbfe-4ba2-bf93-c963153ff791" correct="false" answer="false" feedback="feedback 1"><p class="paragraph">answer 1</p></div><div class="multiple-choice-option" id="810bcf10-4fcb-4d1e-9dab-ce35cbd28527" correct="true" answer="true" feedback="feedback 2"><p class="paragraph">answer 2</p></div></div><div id="d4fa43fc-3a92-4591-a8a4-e6271e42fc02" class="fill-the-gap" feedback="some feedback"><p class="paragraph">first <span id="16ec8f33-db5b-4839-9567-8aa73b776bcf" class="fill-the-gap" answer="">answer1; answer2; answer3</span> second <span id="72f23a71-e774-4834-acba-f357afb6a243" class="fill-the-gap" answer="">answer 4; answer5;</span></p></div>`; const Hhmi = () => { const [submited, isSubmited] = useState(false); const [readOnly, isReadOnly] = useState(false); @@ -55,7 +54,7 @@ const Hhmi = () => { value={t} readonly={readOnly} layout={HhmiLayout} - // onChange={source => console.log(source)} + onChange={source => console.log(source)} /> </> ); diff --git a/wax-prosemirror-services/src/FillTheGapQuestionService/schema/fillTheGapNode.js b/wax-prosemirror-services/src/FillTheGapQuestionService/schema/fillTheGapNode.js index c437d1b3bbbb0fbdb24e0357502c3464aad2bd0f..974d854fce1cf2a7f625883d27cc07a539e16b3e 100644 --- a/wax-prosemirror-services/src/FillTheGapQuestionService/schema/fillTheGapNode.js +++ b/wax-prosemirror-services/src/FillTheGapQuestionService/schema/fillTheGapNode.js @@ -2,7 +2,7 @@ const fillTheGapNode = { attrs: { id: { default: '' }, class: { default: 'fill-the-gap' }, - anser: { default: '' }, + answer: { default: '' }, }, group: 'inline', content: 'text*', diff --git a/wax-prosemirror-services/src/MatchingService/MatchingQuestion.js b/wax-prosemirror-services/src/MatchingService/MatchingQuestion.js index 9894deae5f7c82aaf474905ba1c777d3a4e803fd..552532f99030ded1d54abcfc12de4c7bc48ace4a 100644 --- a/wax-prosemirror-services/src/MatchingService/MatchingQuestion.js +++ b/wax-prosemirror-services/src/MatchingService/MatchingQuestion.js @@ -36,7 +36,7 @@ class MatchingQuestion extends Tools { tr.setSelection(TextSelection.create(tr.doc, range.$to.pos)); const option = state.config.schema.nodes.matching_option.create( - { id: uuidv4() }, + { id: uuidv4(), isfirst: true }, Fragment.empty, ); diff --git a/wax-prosemirror-services/src/MatchingService/components/ContainerEditor.js b/wax-prosemirror-services/src/MatchingService/components/ContainerEditor.js index bab0922f637b0b73c27bc26469c73e67bd6a1fa2..3d9c42641b542ed499d1168243c947d02719c386 100644 --- a/wax-prosemirror-services/src/MatchingService/components/ContainerEditor.js +++ b/wax-prosemirror-services/src/MatchingService/components/ContainerEditor.js @@ -8,7 +8,9 @@ import { StepMap } from 'prosemirror-transform'; import { WaxContext } from 'wax-prosemirror-core'; const EditorWrapper = styled.div` - width: 70% !important; + width: 100% !important; + display: flex; + flex-direction: row; > .ProseMirror { padding: 0px !important; box-shadow: none !important; diff --git a/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js b/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js index 955ae2bbb78063c1629be9668dca7b1ae45e7171..5b9697036ddfbd0c6d2ff963dd44145edca0ce4a 100644 --- a/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js +++ b/wax-prosemirror-services/src/MatchingService/components/DropDownComponent.js @@ -12,6 +12,7 @@ const Wrapper = styled.div` const DropdownStyled = styled(Dropdown)` display: inline-flex; cursor: not-allowed; + margin-left: auto; opacity: ${props => (props.select ? 1 : 0.4)}; pointer-events: ${props => (props.select ? 'default' : 'none')}; .Dropdown-control { @@ -81,7 +82,7 @@ const DropComponent = ({ options }) => { /> </Wrapper> ), - [options], + [], ); return MultipleDropDown; diff --git a/wax-prosemirror-services/src/MatchingService/components/EditorComponent.js b/wax-prosemirror-services/src/MatchingService/components/EditorComponent.js index 0b39e52998e88a5582c01b3879d55b0fdff5ba20..c467ede772d133532a741375a6a747f220adb4f4 100644 --- a/wax-prosemirror-services/src/MatchingService/components/EditorComponent.js +++ b/wax-prosemirror-services/src/MatchingService/components/EditorComponent.js @@ -14,16 +14,16 @@ import Placeholder from '../../MultipleChoiceQuestionService/plugins/placeholder const EditorWrapper = styled.div` border: none; display: flex; - flex: 2 1 auto; - justify-content: left; - width: 100%; + width: 68%; > .ProseMirror { white-space: break-spaces; width: 100% !important; + min-height: 25px !important; word-wrap: break-word; - padding: 0 !important; - border-bottom: 1px solid black; + padding: 4px !important; + border: 12px solid #f4f4f7; + border-radius: 12px; box-shadow: none !important; &:focus { diff --git a/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js b/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js index 1d58dc8982e4697e85fa50b638f675305b6845ec..14dfd9721ae573b1d5109b3b0adb5074e9a95469 100644 --- a/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js +++ b/wax-prosemirror-services/src/MatchingService/components/MatchingContainerComponent.js @@ -1,12 +1,12 @@ /* eslint-disable react/prop-types */ -import React, { useContext, useRef, useState } from 'react'; +import React, { useContext, useEffect, useRef, useState } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { WaxContext } from 'wax-prosemirror-core'; import { Icon } from 'wax-prosemirror-components'; +import { DocumentHelpers } from 'wax-prosemirror-utilities'; import styled from 'styled-components'; import FeedbackComponent from './FeedbackComponent'; import ContainerEditor from './ContainerEditor'; -import DropDownComponent from './DropDownComponent'; const MatchingWrapper = styled.div` display: flex; @@ -24,17 +24,6 @@ const MatchingContainer = styled.div` const QuestionWrapper = styled.div` display: flex; flex-direction: row; -`; - -const InputsContainer = styled.div` - display: flex; - flex-direction: column; - width: 100%; -`; - -const Option = styled.div` - display: flex; - flex-direction: row; width: 100%; `; @@ -91,6 +80,36 @@ const OptionArea = styled.div` const AddOption = styled.div` display: flex; + input { + border: none; + border-bottom: 1px solid black; + &:focus { + outline: none; + } + + ::placeholder { + color: rgb(170, 170, 170); + font-style: italic; + } + } + button { + border: 1px solid #535e76; + cursor: pointer; + color: #535e76; + margin-left: 20px; + background: #fff; + padding: 4px 8px 4px 8px; + &:hover { + border: 1px solid #535e76; + cursor: pointer; + color: #535e76; + margin-right: 20px; + background: #fff; + background: #535e76; + color: #fff; + padding: 4px 8px 4px 8px; + } + } `; export default ({ node, view, getPos }) => { @@ -98,7 +117,8 @@ export default ({ node, view, getPos }) => { const { pmViews: { main }, } = context; - const [options, setOptions] = useState([]); + const [options, setOptions] = useState(node.attrs.options); + const [addingOption, setAddingOption] = useState(false); const addOptionRef = useRef(null); const customProps = main.props.customValues; @@ -113,10 +133,33 @@ export default ({ node, view, getPos }) => { if (addOptionRef.current.value.trim() === '') return; const obj = { label: addOptionRef.current.value, key: uuidv4() }; setOptions(prevOptions => [...prevOptions, obj]); + setAddingOption(true); + setTimeout(() => { + setAddingOption(false); + }); }; + useEffect(() => { + const allNodes = getNodes(main); + if (!addingOption) return; + allNodes.forEach(singleNode => { + if (singleNode.node.attrs.id === node.attrs.id) { + main.dispatch( + main.state.tr.setNodeMarkup(getPos(), undefined, { + ...singleNode.node.attrs, + options, + }), + ); + } + }); + }, [options]); + const removeOption = key => { setOptions(options.filter(option => option.key !== key)); + setAddingOption(true); + setTimeout(() => { + setAddingOption(false); + }); }; return ( @@ -124,38 +167,40 @@ export default ({ node, view, getPos }) => { <span>Matching</span> <MatchingContainer className="matching"> <QuestionWrapper> - <InputsContainer> - <Option> - <ContainerEditor getPos={getPos} node={node} view={view} /> - <DropDownComponent options={options} /> - </Option> - </InputsContainer> + <ContainerEditor getPos={getPos} node={node} view={view} /> </QuestionWrapper> {!readOnly && ( <CreateOptions> <OptionArea> - <ul> - {options.map((option, index) => { - return ( - <li key={option.key}> - <span> - {option.label} - <ActionButton - onClick={() => removeOption(option.key)} - type="button" - > - <StyledIconAction name="deleteOutlined" /> - </ActionButton> - </span> - </li> - ); - })} - </ul> + {options.length > 0 && ( + <ul> + <li>Options: </li> + {options.map((option, index) => { + return ( + <li key={option.key}> + <span> + {option.label} + <ActionButton + onClick={() => removeOption(option.key)} + type="button" + > + <StyledIconAction name="deleteOutlined" /> + </ActionButton> + </span> + </li> + ); + })} + </ul> + )} </OptionArea> <AddOption> - <input placeholder="Add Option" ref={addOptionRef} type="text" /> + <input + placeholder="Type an option ..." + ref={addOptionRef} + type="text" + /> <button onClick={addOption} type="button"> - Add + Add Option </button> </AddOption> </CreateOptions> @@ -172,3 +217,14 @@ export default ({ node, view, getPos }) => { </MatchingWrapper> ); }; + +const getNodes = view => { + const allNodes = DocumentHelpers.findBlockNodes(view.state.doc); + const matchingContainerNodes = []; + allNodes.forEach(node => { + if (node.node.type.name === 'matching_container') { + matchingContainerNodes.push(node); + } + }); + return matchingContainerNodes; +}; diff --git a/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js b/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js index 4a435943f084730c481bc67ecba1169b035ed388..0f492adc6225f1c92b106338281d1e97ed98953c 100644 --- a/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js +++ b/wax-prosemirror-services/src/MatchingService/components/MatchingOptionComponent.js @@ -7,6 +7,27 @@ import styled from 'styled-components'; import { Icon } from 'wax-prosemirror-components'; import { WaxContext } from 'wax-prosemirror-core'; import EditorComponent from './EditorComponent'; +import DropDownComponent from './DropDownComponent'; + +const Option = styled.div` + display: flex; + flex-direction: row; + width: 100%; + padding-bottom: 10px; +`; + +const ButtonsContainer = styled.div` + width: 7%; + display: flex; + flex-direction: column; + justify-content: center; +`; + +const DropDownContainer = styled.div` + display: flex; + justify-content: center; + flex-direction: column; +`; const ActionButton = styled.button` height: 24px; @@ -34,7 +55,6 @@ export default ({ node, view, getPos }) => { const readOnly = !isEditable; const addAnswer = () => { - console.log(node); const nodeId = node.attrs.id; const newAnswerId = uuidv4(); main.state.doc.descendants((editorNode, index) => { @@ -58,14 +78,36 @@ export default ({ node, view, getPos }) => { }); }; + const removeAnswer = () => { + main.state.doc.descendants((sinlgeNode, pos) => { + if (sinlgeNode.attrs.id === node.attrs.id) { + main.dispatch( + main.state.tr.deleteRange(pos, pos + sinlgeNode.nodeSize), + ); + } + }); + }; + + const options = []; + return ( - <> + <Option> {!readOnly && ( - <ActionButton onClick={addAnswer} type="button"> - <StyledIconAction name="plusSquare" /> - </ActionButton> + <ButtonsContainer> + <ActionButton onClick={addAnswer} type="button"> + <StyledIconAction name="plusSquare" /> + </ActionButton> + {!node.attrs.isfirst && ( + <ActionButton onClick={removeAnswer} type="button"> + <StyledIconAction name="deleteOutlined" /> + </ActionButton> + )} + </ButtonsContainer> )} <EditorComponent getPos={getPos} node={node} view={view} /> - </> + <DropDownContainer> + <DropDownComponent options={options} /> + </DropDownContainer> + </Option> ); }; diff --git a/wax-prosemirror-services/src/MatchingService/schema/matchingContainerNode.js b/wax-prosemirror-services/src/MatchingService/schema/matchingContainerNode.js index 6f22b4ccfd2e9a1cbcabe20bd52f2a1061d2303d..8466126a739a0023bbeef53cc5a27c6bac3ab5c8 100644 --- a/wax-prosemirror-services/src/MatchingService/schema/matchingContainerNode.js +++ b/wax-prosemirror-services/src/MatchingService/schema/matchingContainerNode.js @@ -2,7 +2,7 @@ const matchingContainerNode = { attrs: { id: { default: '' }, class: { default: 'matching-container' }, - answers: { default: [] }, + options: { default: [] }, feedback: { default: '' }, }, group: 'block questions', @@ -18,12 +18,22 @@ const matchingContainerNode = { id: dom.getAttribute('id'), class: dom.getAttribute('class'), feedback: dom.getAttribute('feedback'), + options: JSON.parse(dom.getAttribute('options')), }; }, }, ], toDOM(node) { - return ['div', node.attrs, 0]; + return [ + 'div', + { + id: node.attrs.id, + class: node.attrs.class, + options: JSON.stringify(node.attrs.options), + feedback: node.attrs.feedback, + }, + 0, + ]; }, }; diff --git a/wax-prosemirror-services/src/MatchingService/schema/matchingOptionNode.js b/wax-prosemirror-services/src/MatchingService/schema/matchingOptionNode.js index 0e70af423715d8b99d06ef58ca34b35547d25a10..3452cac820d9f6a04a9162c5af6c081127668815 100644 --- a/wax-prosemirror-services/src/MatchingService/schema/matchingOptionNode.js +++ b/wax-prosemirror-services/src/MatchingService/schema/matchingOptionNode.js @@ -2,6 +2,7 @@ const matchingOptionNode = { attrs: { class: { default: 'matching-option' }, id: { default: '' }, + isfirst: { default: false }, correct: { default: false }, answer: { default: false }, }, @@ -17,6 +18,7 @@ const matchingOptionNode = { return { id: dom.getAttribute('id'), class: dom.getAttribute('class'), + isfirst: JSON.parse(dom.getAttribute('isfirst').toLowerCase()), correct: JSON.parse(dom.getAttribute('correct').toLowerCase()), answer: JSON.parse(dom.getAttribute('answer').toLowerCase()), }; diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/components/AnswerComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/components/AnswerComponent.js index 1bb5badc9b9cfa8188f764323dd76ae049cc6bfe..6d8fb34f8a935108dcaf2ae981500874dfb99c12 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/components/AnswerComponent.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/components/AnswerComponent.js @@ -131,10 +131,6 @@ export default ({ node, view, getPos }) => { Fragment.empty, ); main.dispatch(main.state.tr.replaceSelectionWith(answerOption)); - // create Empty Paragraph - setTimeout(() => { - helpers.createEmptyParagraph(context, newAnswerId); - }, 120); } } }); diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseQuestionService/components/AnswerComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseQuestionService/components/AnswerComponent.js index ddc4e4b4bff39d1b96f91034602ce9a78f06f9ee..1d9cea70d89efbe62991e14c7c937b72c1b2fe06 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseQuestionService/components/AnswerComponent.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseQuestionService/components/AnswerComponent.js @@ -130,10 +130,6 @@ export default ({ node, view, getPos }) => { Fragment.empty, ); main.dispatch(main.state.tr.replaceSelectionWith(answerOption)); - // create Empty Paragraph - setTimeout(() => { - helpers.createEmptyParagraph(context, newAnswerId); - }, 120); } } }); diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/components/AnswerComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/components/AnswerComponent.js index 8d86699e386d6defa1322bb5917d9936d48cd541..431d7f6e98c467efc30ff86f7a036d4fd5a70faf 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/components/AnswerComponent.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/components/AnswerComponent.js @@ -130,10 +130,6 @@ export default ({ node, view, getPos }) => { Fragment.empty, ); main.dispatch(main.state.tr.replaceSelectionWith(answerOption)); - // create Empty Paragraph - setTimeout(() => { - helpers.createEmptyParagraph(context, newAnswerId); - }, 120); } } }); diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js index eea45755ee40eb441da9bcda92a0e3c6b6900399..313d88a3223cf7d490489848540a132c01202c28 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/AnswerComponent.js @@ -7,7 +7,6 @@ import { DocumentHelpers } from 'wax-prosemirror-utilities'; import { Fragment } from 'prosemirror-model'; import { v4 as uuidv4 } from 'uuid'; import { Icon } from 'wax-prosemirror-components'; -import helpers from '../helpers/helpers'; import EditorComponent from './EditorComponent'; import SwitchComponent from './SwitchComponent'; import FeedbackComponent from './FeedbackComponent'; @@ -130,10 +129,6 @@ export default ({ node, view, getPos }) => { Fragment.empty, ); main.dispatch(main.state.tr.replaceSelectionWith(answerOption)); - // create Empty Paragraph - // setTimeout(() => { - // helpers.createEmptyParagraph(context, newAnswerId); - // }, 120); } } });