From 98768714f765d1256cfd90c811c324c0714da6dc Mon Sep 17 00:00:00 2001 From: chris <kokosias@yahoo.gr> Date: Mon, 29 Nov 2021 13:50:11 +0200 Subject: [PATCH] true false files --- editors/demo/package.json | 4 +- wax-prosemirror-services/package.json | 2 + .../MultipleChoiceQuestionService.js | 6 +- .../MultipleChoiceSingleCorrectQuestion.js | 2 +- .../TrueFalseNodeView.js | 55 ++++++ .../TrueFalseQuestion.js | 102 +++++++++++ .../TrueFalseQuestionService.js | 28 ++-- .../components/QuestionComponent.js | 158 ++++++++++++++++++ .../components/Switch.js | 52 ++++++ .../components/SwitchComponent.js | 77 +++++++++ .../components/ToolBarBtn.js | 59 +++++++ .../schema/trueFalseContainerNode.js | 27 +++ .../schema/trueFalseNode.js | 30 ++++ .../MultipleDropDown.js | 17 +- 14 files changed, 594 insertions(+), 25 deletions(-) create mode 100644 wax-prosemirror-services/src/TrueFalseQuestionService/components/QuestionComponent.js create mode 100644 wax-prosemirror-services/src/TrueFalseQuestionService/components/Switch.js create mode 100644 wax-prosemirror-services/src/TrueFalseQuestionService/components/SwitchComponent.js create mode 100644 wax-prosemirror-services/src/TrueFalseQuestionService/components/ToolBarBtn.js create mode 100644 wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseContainerNode.js create mode 100644 wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseNode.js diff --git a/editors/demo/package.json b/editors/demo/package.json index c157e23df..2a6658f79 100644 --- a/editors/demo/package.json +++ b/editors/demo/package.json @@ -1,12 +1,10 @@ { - "name": "editoria", + "name": "demo", "version": "0.2.0", "private": true, "dependencies": { - "@ant-design/icons": "^4.6.2", "@guardian/prosemirror-invisibles": "^1.2.0", "@pubsweet/ui-toolkit": "^2.3.1", - "antd": "^4.15.4", "fontsource-merriweather": "^3.0.9", "prosemirror-tables": "^1.1.1", "react": "^16.13.1", diff --git a/wax-prosemirror-services/package.json b/wax-prosemirror-services/package.json index 0fe6fce7a..bf2f48de1 100644 --- a/wax-prosemirror-services/package.json +++ b/wax-prosemirror-services/package.json @@ -14,6 +14,8 @@ "build": "BABEL_ENV=production rollup -c" }, "dependencies": { + "@ant-design/icons": "^4.6.2", + "antd": "^4.15.4", "inversify": "^5.0.1", "inversify-inject-decorators": "^3.1.0", "lodash": "^4.17.4", diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js index 9053ec2e2..746eb8726 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js @@ -5,6 +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'; class MultipleChoiceQuestionService extends Service { register() { @@ -27,7 +28,10 @@ class MultipleChoiceQuestionService extends Service { }); } - dependencies = [new MultipleChoiceSingleCorrectQuestionService()]; + dependencies = [ + new MultipleChoiceSingleCorrectQuestionService(), + new TrueFalseQuestionService(), + ]; } export default MultipleChoiceQuestionService; diff --git a/wax-prosemirror-services/src/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestion.js b/wax-prosemirror-services/src/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestion.js index 76c4d9eee..242b6d54e 100644 --- a/wax-prosemirror-services/src/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestion.js +++ b/wax-prosemirror-services/src/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestion.js @@ -6,9 +6,9 @@ import { v4 as uuidv4 } from 'uuid'; import { Fragment } from 'prosemirror-model'; import { TextSelection } from 'prosemirror-state'; import { wrapIn } from 'prosemirror-commands'; +import ToolBarBtn from './components/ToolBarBtn'; import helpers from '../MultipleChoiceQuestionService/helpers/helpers'; import Tools from '../lib/Tools'; -import ToolBarBtn from './components/ToolBarBtn'; const checkifEmpty = view => { const { state } = view; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseNodeView.js b/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseNodeView.js index e69de29bb..ac4d019f5 100644 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseNodeView.js +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseNodeView.js @@ -0,0 +1,55 @@ +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 index e69de29bb..67f7ae254 100644 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestion.js +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestion.js @@ -0,0 +1,102 @@ +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 './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 index eb82a0962..8da8559c1 100644 --- a/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestionService.js +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/TrueFalseQuestionService.js @@ -1,8 +1,8 @@ import Service from '../Service'; import TrueFalseQuestion from './TrueFalseQuestion'; -// import multipleChoiceSingleCorrectNode from './schema/multipleChoiceSingleCorrectNode'; -// import multipleChoiceSingleCorrectContainerNode from './schema/multipleChoiceSingleCorrectContainerNode'; -// import QuestionComponent from './components/QuestionComponent'; +import trueFalseNode from './schema/trueFalseNode'; +import trueFalseContainerNode from './schema/trueFalseContainerNode'; +import QuestionComponent from './components/QuestionComponent'; import TrueFalseNodeView from './TrueFalseNodeView'; class TrueFalseQuestionService extends Service { @@ -11,19 +11,19 @@ class TrueFalseQuestionService extends Service { const createNode = this.container.get('CreateNode'); const addPortal = this.container.get('AddPortal'); - // createNode({ - // multiple_choice_single_correct: multipleChoiceSingleCorrectNode, - // }); + createNode({ + true_false_container: trueFalseContainerNode, + }); - // createNode({ - // multiple_choice_single_correct_container: multipleChoiceSingleCorrectContainerNode, - // }); + createNode({ + true_false: trueFalseNode, + }); - // addPortal({ - // nodeView: TrueFalseNodeView, - // component: QuestionComponent, - // context: this.app, - // }); + addPortal({ + nodeView: TrueFalseNodeView, + component: QuestionComponent, + context: this.app, + }); } } diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/components/QuestionComponent.js b/wax-prosemirror-services/src/TrueFalseQuestionService/components/QuestionComponent.js new file mode 100644 index 000000000..8717560b1 --- /dev/null +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/components/QuestionComponent.js @@ -0,0 +1,158 @@ +/* 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/Switch.js b/wax-prosemirror-services/src/TrueFalseQuestionService/components/Switch.js new file mode 100644 index 000000000..6cad91dad --- /dev/null +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/components/Switch.js @@ -0,0 +1,52 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled, { css } from 'styled-components'; +import { Switch as AntSwitch } from 'antd'; + +import { grid } from '@pubsweet/ui-toolkit'; + +const Wrapper = styled.span``; + +const Label = styled.span` + ${props => + props.labelPosition === 'left' && + css` + margin-right: ${grid(2)}; + `} + + ${props => + props.labelPosition === 'right' && + css` + margin-left: ${grid(2)}; + `} +`; + +const Switch = props => { + const { className, label, labelPosition, ...rest } = props; + + return ( + <Wrapper className={className}> + {label && labelPosition === 'left' && ( + <Label labelPosition={labelPosition}>{label}</Label> + )} + + <AntSwitch {...rest} /> + + {label && labelPosition === 'right' && ( + <Label labelPosition={labelPosition}>{label}</Label> + )} + </Wrapper> + ); +}; + +Switch.propTypes = { + label: PropTypes.string, + labelPosition: PropTypes.string, +}; + +Switch.defaultProps = { + label: null, + labelPosition: 'right', +}; + +export default Switch; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/components/SwitchComponent.js b/wax-prosemirror-services/src/TrueFalseQuestionService/components/SwitchComponent.js new file mode 100644 index 000000000..f0db85d5a --- /dev/null +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/components/SwitchComponent.js @@ -0,0 +1,77 @@ +/* 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 './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="YES" + label="Correct?" + labelPosition="left" + onChange={handleChange} + unCheckedChildren="NO" + /> + ); +}; + +const getNodes = view => { + const allNodes = DocumentHelpers.findBlockNodes(view.state.doc); + const multipleChoiceNodes = []; + allNodes.forEach(node => { + if (node.node.type.name === 'multiple_choice_single_correct') { + multipleChoiceNodes.push(node); + } + }); + return multipleChoiceNodes; +}; + +export default CustomSwitch; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/components/ToolBarBtn.js b/wax-prosemirror-services/src/TrueFalseQuestionService/components/ToolBarBtn.js new file mode 100644 index 000000000..d583f3b18 --- /dev/null +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/components/ToolBarBtn.js @@ -0,0 +1,59 @@ +/* eslint react/prop-types: 0 */ +import React, { useContext, useMemo } from 'react'; +import { WaxContext } from 'wax-prosemirror-core'; +import styled, { css } from 'styled-components'; +import { MenuButton } from 'wax-prosemirror-components'; + +const activeStyles = css` + pointer-events: none; +`; + +const StyledButton = styled(MenuButton)` + ${props => props.active && activeStyles} +`; + +const ToolBarBtn = ({ view = {}, item }) => { + const { active, icon, label, onlyOnMain, run, select, title } = item; + const context = useContext(WaxContext); + const { + view: { main }, + activeViewId, + activeView, + } = useContext(WaxContext); + + if (onlyOnMain) view = main; + + const isEditable = main.props.editable(editable => { + return editable; + }); + + const { state } = view; + + const isActive = !!( + active(state, activeViewId) && select(state, activeViewId) + ); + + let isDisabled = !select(state, activeView); + if (!isEditable) isDisabled = true; + + const ToolBarBtnComponent = useMemo( + () => ( + <StyledButton + active={isActive || false} + disabled={isDisabled} + iconName={icon} + label={label} + onMouseDown={e => { + e.preventDefault(); + item.run(view, main, context); + }} + title={title} + /> + ), + [isActive, isDisabled], + ); + + return ToolBarBtnComponent; +}; + +export default ToolBarBtn; diff --git a/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseContainerNode.js b/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseContainerNode.js new file mode 100644 index 000000000..23f5a11e5 --- /dev/null +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseContainerNode.js @@ -0,0 +1,27 @@ +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 new file mode 100644 index 000000000..2d9c0de70 --- /dev/null +++ b/wax-prosemirror-services/src/TrueFalseQuestionService/schema/trueFalseNode.js @@ -0,0 +1,30 @@ +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; diff --git a/wax-prosemirror-services/src/WaxToolGroups/MultipleDropDownToolGroupService/MultipleDropDown.js b/wax-prosemirror-services/src/WaxToolGroups/MultipleDropDownToolGroupService/MultipleDropDown.js index b3ced223a..99a2b14cc 100644 --- a/wax-prosemirror-services/src/WaxToolGroups/MultipleDropDownToolGroupService/MultipleDropDown.js +++ b/wax-prosemirror-services/src/WaxToolGroups/MultipleDropDownToolGroupService/MultipleDropDown.js @@ -15,9 +15,14 @@ class MultipleDropDown extends ToolGroup { @inject('MultipleChoiceQuestion') multipleChoiceQuestion, @inject('MultipleChoiceSingleCorrectQuestion') multipleChoiceSingleCorrectQuestion, + @inject('TrueFalseQuestion') trueFalseQuestion, ) { super(); - this.tools = [multipleChoiceQuestion, multipleChoiceSingleCorrectQuestion]; + this.tools = [ + multipleChoiceQuestion, + multipleChoiceSingleCorrectQuestion, + trueFalseQuestion, + ]; } renderTools(view) { @@ -74,11 +79,11 @@ class MultipleDropDown extends ToolGroup { value: '1', item: this._tools[1], }, - // { - // label: 'True/False', - // value: '2', - // item: this._tools[0], - // }, + { + label: 'True/False', + value: '2', + item: this._tools[2], + }, // { // label: 'True/False (single correct)', // value: '3', -- GitLab