diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js index 746eb8726d2775f8a9647741feef67aee88d413c..19dd84be7cdcecfdf1a3767bd5157410f5a04125 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js @@ -5,7 +5,7 @@ import multipleChoiceContainerNode from './schema/multipleChoiceContainerNode'; import QuestionComponent from './components/QuestionComponent'; import MultipleChoiceNodeView from './MultipleChoiceNodeView'; import MultipleChoiceSingleCorrectQuestionService from '../MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestionService'; -import TrueFalseQuestionService from '../TrueFalseQuestionService/TrueFalseQuestionService'; +import TrueFalseQuestionService from './TrueFalseQuestionService/TrueFalseQuestionService'; class MultipleChoiceQuestionService extends Service { register() { diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseNodeView.js b/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseNodeView.js deleted file mode 100644 index ac4d019f579c57c6a5fda190ed65239e6f974bfe..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseNodeView.js +++ /dev/null @@ -1,55 +0,0 @@ -import AbstractNodeView from '../PortalService/AbstractNodeView'; - -export default class TrueFalseNodeView extends AbstractNodeView { - constructor( - node, - view, - getPos, - decorations, - createPortal, - Component, - context, - ) { - super(node, view, getPos, decorations, createPortal, Component, context); - - this.node = node; - this.outerView = view; - this.getPos = getPos; - this.context = context; - } - - static name() { - return 'true_false'; - } - - update(node) { - this.node = node; - if (this.context.view[node.attrs.id]) { - const { state } = this.context.view[node.attrs.id]; - const start = node.content.findDiffStart(state.doc.content); - if (start != null) { - let { a: endA, b: endB } = node.content.findDiffEnd(state.doc.content); - const overlap = start - Math.min(endA, endB); - if (overlap > 0) { - endA += overlap; - endB += overlap; - } - this.context.view[node.attrs.id].dispatch( - state.tr - .replace(start, endB, node.slice(start, endA)) - .setMeta('fromOutside', true), - ); - } - } - - return true; - } - - stopEvent(event) { - if (event.target.type === 'text') { - return true; - } - const innerView = this.context.view[this.node.attrs.id]; - return innerView && innerView.dom.contains(event.target); - } -} diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestion.js b/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestion.js deleted file mode 100644 index 590afd6fa06dc5f6e81bec8032d38d7e3f8691bd..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestion.js +++ /dev/null @@ -1,102 +0,0 @@ -import React from 'react'; -import { isEmpty } from 'lodash'; -import { injectable } from 'inversify'; -import { Commands } from 'wax-prosemirror-utilities'; -import { v4 as uuidv4 } from 'uuid'; -import { Fragment } from 'prosemirror-model'; -import { TextSelection } from 'prosemirror-state'; -import { wrapIn } from 'prosemirror-commands'; -import ToolBarBtn from '../MultipleChoiceQuestionService/components/ToolBarBtn'; -import helpers from '../MultipleChoiceQuestionService/helpers/helpers'; -import Tools from '../lib/Tools'; - -const checkifEmpty = view => { - const { state } = view; - const { from, to } = state.selection; - state.doc.nodesBetween(from, to, (node, pos) => { - if (node.textContent !== ' ') Commands.simulateKey(view, 13, 'Enter'); - }); -}; - -const createOption = (main, context) => { - const { state, dispatch } = main; - /* Create Wrapping */ - const { $from, $to } = state.selection; - const range = $from.blockRange($to); - - wrapIn(state.config.schema.nodes.true_false_container, { - id: uuidv4(), - })(state, dispatch); - - /* set New Selection */ - dispatch( - main.state.tr.setSelection( - new TextSelection(main.state.tr.doc.resolve(range.$to.pos)), - ), - ); - - /* create Second Option */ - const newAnswerId = uuidv4(); - const answerOption = main.state.config.schema.nodes.true_false.create( - { id: newAnswerId }, - Fragment.empty, - ); - dispatch(main.state.tr.replaceSelectionWith(answerOption)); - setTimeout(() => { - helpers.createEmptyParagraph(context, newAnswerId); - }, 50); -}; - -@injectable() -class MultipleChoiceQuestion extends Tools { - title = 'Add True False Question'; - icon = 'multipleChoice'; - name = 'TrueFalse'; - label = 'True False'; - - get run() { - return (view, main, context) => { - checkifEmpty(view); - createOption(main, context); - }; - } - - get active() { - return state => { - return Commands.isParentOfType( - state, - state.config.schema.nodes.true_false, - ); - }; - } - - select = (state, activeView) => { - const { disallowedTools } = activeView.props; - if (disallowedTools.includes('MultipleChoice')) return false; - let status = true; - const { from, to } = state.selection; - - if (from === null) return false; - - state.doc.nodesBetween(from, to, (node, pos) => { - if (node.type.groups.includes('questions')) { - status = false; - } - }); - return status; - }; - - get enable() { - return state => {}; - } - - renderTool(view) { - if (isEmpty(view)) return null; - // eslint-disable-next-line no-underscore-dangle - return this._isDisplayed ? ( - <ToolBarBtn item={this.toJSON()} key={uuidv4()} view={view} /> - ) : null; - } -} - -export default MultipleChoiceQuestion; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestionService.js b/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestionService.js deleted file mode 100644 index 8da8559c193ba02da6b367d49d9847699db3ef71..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestionService.js +++ /dev/null @@ -1,30 +0,0 @@ -import Service from '../Service'; -import TrueFalseQuestion from './TrueFalseQuestion'; -import trueFalseNode from './schema/trueFalseNode'; -import trueFalseContainerNode from './schema/trueFalseContainerNode'; -import QuestionComponent from './components/QuestionComponent'; -import TrueFalseNodeView from './TrueFalseNodeView'; - -class TrueFalseQuestionService extends Service { - register() { - this.container.bind('TrueFalseQuestion').to(TrueFalseQuestion); - const createNode = this.container.get('CreateNode'); - const addPortal = this.container.get('AddPortal'); - - createNode({ - true_false_container: trueFalseContainerNode, - }); - - createNode({ - true_false: trueFalseNode, - }); - - addPortal({ - nodeView: TrueFalseNodeView, - component: QuestionComponent, - context: this.app, - }); - } -} - -export default TrueFalseQuestionService; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/components/QuestionComponent.js b/wax-prosemirror-services/src/TrueFalseQuestionService/components/QuestionComponent.js deleted file mode 100644 index 8717560b16e3f83da4b0c2e3d49a2636326e27aa..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/components/QuestionComponent.js +++ /dev/null @@ -1,158 +0,0 @@ -/* eslint-disable react/prop-types */ -import React, { useContext } from 'react'; -import styled from 'styled-components'; -import { TextSelection } from 'prosemirror-state'; -import { WaxContext } from 'wax-prosemirror-core'; -import { PlusSquareOutlined, DeleteOutlined } from '@ant-design/icons'; -import { Fragment } from 'prosemirror-model'; -import { v4 as uuidv4 } from 'uuid'; -import helpers from '../../MultipleChoiceQuestionService/helpers/helpers'; -import FeedbackComponent from '../../MultipleChoiceQuestionService/components/FeedbackComponent'; -import EditorComponent from '../../MultipleChoiceQuestionService/components/EditorComponent'; -import Button from '../../MultipleChoiceQuestionService/components/Button'; -import SwitchComponent from './SwitchComponent'; - -const Wrapper = styled.div` - display: flex; - flex-direction: row; - width: 100%; -`; - -const InfoRow = styled.div` - color: black; - display: flex; - flex-direction: row; - padding: 10px 0px 4px 0px; -`; - -const QuestionNunber = styled.span` - &:before { - content: 'Answer ' counter(question-item-multiple); - counter-increment: question-item-multiple; - } -`; - -const QuestionControlsWrapper = styled.div` - display: flex; - flex-direction: column; - width: 100%; -`; - -const QuestionWrapper = styled.div` - border: 1px solid #a5a1a2; - border-radius: 4px; - color: black; - display: flex; - flex: 2 1 auto; - flex-direction: column; - padding: 10px; -`; - -const IconsWrapper = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - - button { - border: none; - box-shadow: none; - } - - span { - cursor: pointer; - } -`; - -const QuestionData = styled.div` - align-items: normal; - display: flex; - flex-direction: row; -`; - -export default ({ node, view, getPos }) => { - const context = useContext(WaxContext); - const { - view: { main }, - } = context; - - const isEditable = main.props.editable(editable => { - return editable; - }); - - const removeOption = () => { - main.state.doc.nodesBetween(getPos(), getPos() + 1, (sinlgeNode, pos) => { - if (sinlgeNode.attrs.id === node.attrs.id) { - main.dispatch( - main.state.tr.deleteRange(getPos(), getPos() + sinlgeNode.nodeSize), - ); - } - }); - }; - - const addOption = nodeId => { - const newAnswerId = uuidv4(); - context.view.main.state.doc.descendants((editorNode, index) => { - if (editorNode.type.name === 'true_false') { - if (editorNode.attrs.id === nodeId) { - context.view.main.dispatch( - context.view.main.state.tr.setSelection( - new TextSelection( - context.view.main.state.tr.doc.resolve( - editorNode.nodeSize + index, - ), - ), - ), - ); - - const answerOption = context.view.main.state.config.schema.nodes.multiple_choice.create( - { id: newAnswerId }, - Fragment.empty, - ); - context.view.main.dispatch( - context.view.main.state.tr.replaceSelectionWith(answerOption), - ); - // create Empty Paragraph - setTimeout(() => { - helpers.createEmptyParagraph(context, newAnswerId); - }, 120); - } - } - }); - }; - - const readOnly = !isEditable; - const showAddIcon = true; - const showRemoveIcon = true; - - return ( - <Wrapper> - <QuestionControlsWrapper> - <InfoRow> - <QuestionNunber /> - <SwitchComponent getPos={getPos} node={node} /> - </InfoRow> - <QuestionWrapper> - <QuestionData> - <EditorComponent getPos={getPos} node={node} view={view} /> - </QuestionData> - <FeedbackComponent getPos={getPos} node={node} view={view} /> - </QuestionWrapper> - </QuestionControlsWrapper> - <IconsWrapper> - {showAddIcon && !readOnly && ( - <Button - icon={<PlusSquareOutlined title="Add Option" />} - onClick={() => addOption(node.attrs.id)} - /> - )} - {showRemoveIcon && !readOnly && ( - <Button - icon={ - <DeleteOutlined onClick={removeOption} title="Delete Option" /> - } - /> - )} - </IconsWrapper> - </Wrapper> - ); -}; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/components/SwitchComponent.js b/wax-prosemirror-services/src/TrueFalseQuestionService/components/SwitchComponent.js deleted file mode 100644 index 162d30a4ab257c030bc878750812f6f61da6f795..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/components/SwitchComponent.js +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable react/prop-types */ - -import React, { useState, useContext, useEffect } from 'react'; -import { WaxContext } from 'wax-prosemirror-core'; -import { DocumentHelpers } from 'wax-prosemirror-utilities'; -import styled from 'styled-components'; -import Switch from '../../MultipleChoiceQuestionService/components/Switch'; - -const StyledSwitch = styled(Switch)` - display: flex; - margin-left: auto; - - span:nth-child(1) { - // bottom: 36px; - // display: flex; - // left: 4px; - // position: relative; - // width: 0px; - } - - .ant-switch-checked { - background-color: green; - } -`; - -const CustomSwitch = ({ node, getPos }) => { - const context = useContext(WaxContext); - const [checked, setChecked] = useState(false); - - useEffect(() => { - const allNodes = getNodes(context.view.main); - allNodes.forEach(singNode => { - if (singNode.node.attrs.id === node.attrs.id) { - setChecked(singNode.node.attrs.correct); - } - }); - }, [getNodes(context.view.main)]); - - const handleChange = () => { - setChecked(!checked); - const allNodes = getNodes(context.view.main); - allNodes.forEach(singleNode => { - if (singleNode.node.attrs.id === node.attrs.id) { - context.view.main.dispatch( - context.view.main.state.tr.setNodeMarkup(getPos(), undefined, { - ...singleNode.node.attrs, - correct: !checked, - }), - ); - } - }); - }; - - return ( - <StyledSwitch - checked={checked} - checkedChildren="True" - label="True/false?" - labelPosition="left" - onChange={handleChange} - unCheckedChildren="False" - /> - ); -}; - -const getNodes = view => { - const allNodes = DocumentHelpers.findBlockNodes(view.state.doc); - const multipleChoiceNodes = []; - allNodes.forEach(node => { - if (node.node.type.name === 'true_false') { - multipleChoiceNodes.push(node); - } - }); - return multipleChoiceNodes; -}; - -export default CustomSwitch; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseContainerNode.js b/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseContainerNode.js deleted file mode 100644 index 23f5a11e51aee942eb7ca051cba2584db691fe39..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseContainerNode.js +++ /dev/null @@ -1,27 +0,0 @@ -const trueFalseContainerNode = { - attrs: { - id: { default: '' }, - class: { default: 'true-false' }, - }, - group: 'block questions', - atom: true, - selectable: true, - draggable: true, - content: 'true_false+', - parseDOM: [ - { - tag: 'div.true-false', - getAttrs(dom) { - return { - id: dom.dataset.id, - class: dom.getAttribute('class'), - }; - }, - }, - ], - toDOM(node) { - return ['div', node.attrs, 0]; - }, -}; - -export default trueFalseContainerNode; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseNode.js b/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseNode.js deleted file mode 100644 index 2d9c0de706a3aadc1e0b7f118e12588bf70d5a11..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseNode.js +++ /dev/null @@ -1,30 +0,0 @@ -import { v4 as uuidv4 } from 'uuid'; - -const trueFalseNode = { - attrs: { - class: { default: 'true-false-option' }, - id: { default: uuidv4() }, - correct: { default: false }, - feedback: { default: '' }, - }, - group: 'block questions', - content: 'block*', - defining: true, - - parseDOM: [ - { - tag: 'div.true-false-option', - getAttrs(dom) { - return { - id: dom.getAttribute('id'), - class: dom.getAttribute('class'), - correct: JSON.parse(dom.getAttribute('correct').toLowerCase()), - feedback: dom.getAttribute('feedback'), - }; - }, - }, - ], - toDOM: node => ['div', node.attrs, 0], -}; - -export default trueFalseNode;