diff --git a/editors/demo/src/Editoria/config/config.js b/editors/demo/src/Editoria/config/config.js index 65fa24bc4361e60250a7a78c36bf0490d3ffd935..43e4e487dc8ae2f767f23472aa0b0d64bc74335b 100644 --- a/editors/demo/src/Editoria/config/config.js +++ b/editors/demo/src/Editoria/config/config.js @@ -149,7 +149,7 @@ export default { }, }, PmPlugins: [ - // tableEditing(), + tableEditing(), columnResizing(), invisibles([hardBreak()]), disallowPasteImagesPlugin(() => diff --git a/editors/demo/src/HHMI/config/config.js b/editors/demo/src/HHMI/config/config.js index 2ae6496a69b42bcfa52c64959d8a110ff9d687dc..5d6e72a03f2d73b94432cc1eb3b0b17a495c54f5 100644 --- a/editors/demo/src/HHMI/config/config.js +++ b/editors/demo/src/HHMI/config/config.js @@ -54,7 +54,7 @@ export default { RulesService: [emDash, ellipsis], ImageService: { showAlt: true }, - PmPlugins: [invisibles([hardBreak()])], + PmPlugins: [invisibles([hardBreak()]), tableEditing(), columnResizing()], services: [ new QuestionsService(), new ListsService(), diff --git a/wax-prosemirror-core/src/config/defaultServices/ShortCutsService/ShortCuts.js b/wax-prosemirror-core/src/config/defaultServices/ShortCutsService/ShortCuts.js index b6f5ad26d6ea07cd2757c44c9cd7f33843429f00..f6b9ec07afec499350ef14136408e0a076cfbbe5 100644 --- a/wax-prosemirror-core/src/config/defaultServices/ShortCutsService/ShortCuts.js +++ b/wax-prosemirror-core/src/config/defaultServices/ShortCutsService/ShortCuts.js @@ -35,8 +35,14 @@ const backSpaceShortCut = (state, dispatch, view) => { } state.doc.nodesBetween($from.pos, $to.pos, (node, from) => { - if (node.type.name === 'fill_the_gap_container') { - // dispatch(state.tr.delete(from, from + node.nodeSize)); + if ( + node.type.name === 'fill_the_gap_container' || + node.type.name === 'multiple_drop_down_container' || + node.type.name === 'numerical_answer_container' || + node.type.name === 'essay_container' || + node.type.name === 'matching_container' + ) { + dispatch(state.tr.delete(from, from + node.nodeSize)); // const index = $from.index($from.depth); // const $beforePos = state.doc.resolve($from.posAtIndex(index - 1)); // dispatch(state.tr.setSelection(new NodeSelection($beforePos))); diff --git a/wax-prosemirror-core/src/config/plugins/FakeCursorPlugin.js b/wax-prosemirror-core/src/config/plugins/FakeCursorPlugin.js index c53bd01f9b55a17a5466f46a0c381f82f7e0a8f1..b4cb4734a38afa1c6c6411d16fac369ea8a30316 100644 --- a/wax-prosemirror-core/src/config/plugins/FakeCursorPlugin.js +++ b/wax-prosemirror-core/src/config/plugins/FakeCursorPlugin.js @@ -11,27 +11,34 @@ export default props => { init: (_, state) => {}, apply(tr, prev, _, newState) { let createDecoration; - const widget = document.createElement('span'); - widget.setAttribute('id', 'fake-cursor'); - if (newState.selection.from === newState.selection.to) { - createDecoration = DecorationSet.create(newState.doc, [ - Decoration.widget(newState.selection.from, widget, { - key: 'fakecursor', - }), - ]); - } - setTimeout(() => { - widget.setAttribute('contenteditable', true); - if ( - navigator.userAgent.includes('Firefox') && - newState.selection.$from.nodeBefore === null - ) { - widget.setAttribute('style', 'visibility:hidden'); - } else { - widget.setAttribute('style', 'display:none'); + if ( + tr.steps.length === 0 || + (tr.steps[0] && tr.steps[0].from === tr.steps[0].to) + ) { + const widget = document.createElement('span'); + widget.setAttribute('id', 'fake-cursor'); + + if (newState.selection.from === newState.selection.to) { + createDecoration = DecorationSet.create(newState.doc, [ + Decoration.widget(newState.selection.from, widget, { + key: 'fakecursor', + }), + ]); } - }); + setTimeout(() => { + widget.setAttribute('contenteditable', true); + if ( + navigator.userAgent.includes('Firefox') && + newState.selection.$from.nodeBefore === null + ) { + widget.setAttribute('style', 'visibility:hidden'); + } else { + widget.setAttribute('style', 'display:none'); + } + }); + } + return { createDecoration, }; diff --git a/wax-prosemirror-core/src/styles/styles.css b/wax-prosemirror-core/src/styles/styles.css index 802fced80c1a51aabdad7269415c4118d3472573..c8a9e456b75af535c5c32727e1d0302c50952817 100644 --- a/wax-prosemirror-core/src/styles/styles.css +++ b/wax-prosemirror-core/src/styles/styles.css @@ -235,7 +235,7 @@ img.ProseMirror-separator { } span#fake-cursor::before { - display: inline; + display: inline-flex; content: ''; border-right: 1px solid black; height: 23px; diff --git a/wax-prosemirror-core/src/utilities/commands/Commands.js b/wax-prosemirror-core/src/utilities/commands/Commands.js index 563bd74239fd0225f9ad1f84275a9206ea7b2c9c..90f7b1ad8b131c1535c5fccc2059b6fd2aeb0569 100644 --- a/wax-prosemirror-core/src/utilities/commands/Commands.js +++ b/wax-prosemirror-core/src/utilities/commands/Commands.js @@ -1,3 +1,4 @@ +/* eslint-disable no-multi-assign */ import { v4 as uuidv4 } from 'uuid'; import { toggleMark } from 'prosemirror-commands'; import { AddMarkStep } from 'prosemirror-transform'; @@ -135,11 +136,19 @@ const createComment = ( viewid, conversation = [], title = '', + posFrom, + posTo, ) => { const { selection: { $from, $to }, tr, } = state; + let fromPosition = $from.pos; + let toPosition = $to.pos; + if ($from.pos === $to.pos) { + fromPosition = posFrom; + toPosition = posTo; + } let footnote = false; let footnoteNode; state.doc.nodesBetween($from.pos, $to.pos, (node, from) => { @@ -172,13 +181,21 @@ const createComment = ( title, ); } - - toggleMark(state.config.schema.marks.comment, { - id: uuidv4(), - group, - conversation, - viewid, - })(state, dispatch); + dispatch( + state.tr + .addMark( + fromPosition, + toPosition, + state.config.schema.marks.comment.create({ + id: uuidv4(), + group, + viewid, + conversation, + title, + }), + ) + .setMeta('forceUpdate', true), + ); }; const createCommentOnSingleFootnote = ( diff --git a/wax-prosemirror-services/index.js b/wax-prosemirror-services/index.js index af898118e764e1904a5b2276ba1f691c6ab8f193..95b5a5596a5545d5e9c7daf290e380fdae1736fa 100644 --- a/wax-prosemirror-services/index.js +++ b/wax-prosemirror-services/index.js @@ -22,7 +22,6 @@ export { default as ShortCutsInfoService } from './src/BottomInfoService/ShortCu export { default as BottomInfoService } from './src/BottomInfoService/BottomInfoService'; export { default as TransformService } from './src/TransformService/TransformService'; export { default as EditingSuggestingService } from './src/EditingSuggestingService/EditingSuggestingService'; -export { default as TrackOptionsService } from './src/TrackOptionsService/TrackOptionsService'; export { default as CustomTagInlineService } from './src/CustomTagService/CustomTagInlineService/CustomTagInlineService'; export { default as CustomTagBlockService } from './src/CustomTagService/CustomTagBlockService/CustomTagBlockService'; export { default as CustomTagService } from './src/CustomTagService/CustomTagService'; diff --git a/wax-prosemirror-services/src/CommentsService/components/ConnectedComment.js b/wax-prosemirror-services/src/CommentsService/components/ConnectedComment.js index e9fad52a9e40d2524603e60613da2314bded7475..b119fc666f5f4c8e40a616bf5cb65b11738925e6 100644 --- a/wax-prosemirror-services/src/CommentsService/components/ConnectedComment.js +++ b/wax-prosemirror-services/src/CommentsService/components/ConnectedComment.js @@ -2,10 +2,9 @@ /* eslint react/prop-types: 0 */ import React, { useContext, useMemo, useState, useEffect } from 'react'; import { TextSelection } from 'prosemirror-state'; -import { last, maxBy } from 'lodash'; +import { last, maxBy, minBy } from 'lodash'; import styled from 'styled-components'; import { WaxContext, DocumentHelpers, Commands } from 'wax-prosemirror-core'; -import { v4 as uuidv4 } from 'uuid'; import { override } from '@pubsweet/ui-toolkit'; import CommentBox from './ui/comments/CommentBox'; @@ -72,64 +71,6 @@ export default ({ comment, top, commentId, recalculateTops, users }) => { } }, [activeComment]); - // const onClickPost = ({ commentValue, title }) => { - // setClickPost(true); - // const currentUser = user || (users || []).find(u => u.currentUser === true); - - // const obj = { - // content: commentValue, - // displayName: currentUser - // ? currentUser.displayName || currentUser.username - // : 'Anonymous', - // userId: currentUser ? currentUser.userId : '1', - // timestamp: Math.floor(Date.now()), - // }; - - // comment.attrs.title = title || comment.attrs.title; - // comment.attrs.conversation.push(obj); - - // const id = uuidv4(); - // allCommentsWithSameId.forEach(singleComment => { - // activeView.dispatch( - // activeView.state.tr.removeMark( - // singleComment.pos, - // singleComment.pos + singleComment.node.nodeSize, - // commentMark, - // ), - // ); - - // if (activeViewId !== 'main') { - // activeView.dispatch( - // activeView.state.tr - // .addMark( - // singleComment.pos, - // singleComment.pos + singleComment.node.nodeSize, - // commentMark.create({ - // id, - // group: comment.attrs.group, - // viewid: comment.attrs.viewid, - // conversation: comment.attrs.conversation, - // title: comment.attrs.title, - // }), - // ) - // .setMeta('forceUpdate', true), - // ); - // } - // }); - - // if (activeViewId === 'main') { - // Commands.createComment( - // pmViews.main.state, - // pmViews.main.dispatch, - // comment.attrs.group, - // comment.attrs.viewid, - // comment.attrs.conversation, - // ); - // } - // activeView.focus(); - // recalculateTops(); - // }; - const onClickPost = ({ commentValue, title }) => { setClickPost(true); const currentUser = user || (users || []).find(u => u.currentUser === true); @@ -146,7 +87,6 @@ export default ({ comment, top, commentId, recalculateTops, users }) => { comment.attrs.title = title || comment.attrs.title; comment.attrs.conversation.push(obj); - const id = uuidv4(); allCommentsWithSameId.forEach(singleComment => { activeView.dispatch( activeView.state.tr.removeMark( @@ -155,23 +95,22 @@ export default ({ comment, top, commentId, recalculateTops, users }) => { commentMark, ), ); - - activeView.dispatch( - activeView.state.tr - .addMark( - singleComment.pos, - singleComment.pos + singleComment.node.nodeSize, - commentMark.create({ - id, - group: comment.attrs.group, - viewid: comment.attrs.viewid, - conversation: comment.attrs.conversation, - title: comment.attrs.title, - }), - ) - .setMeta('forceUpdate', true), - ); }); + + const minPos = minBy(allCommentsWithSameId, 'pos'); + const maxPos = maxBy(allCommentsWithSameId, 'pos'); + + Commands.createComment( + activeView.state, + activeView.dispatch, + comment.attrs.group, + comment.attrs.viewid, + comment.attrs.conversation, + comment.attrs.title, + minPos.pos, + maxPos.pos + last(allCommentsWithSameId).node.nodeSize, + ); + activeView.focus(); recalculateTops(); }; diff --git a/wax-prosemirror-services/src/FindAndReplaceService/components/FindAndReplaceTool.js b/wax-prosemirror-services/src/FindAndReplaceService/components/FindAndReplaceTool.js index da57e23fc80a59e65ddd646b8e06b8888af80c62..986968f53b4d69822bdabab9eb66dbc28d77b0e8 100644 --- a/wax-prosemirror-services/src/FindAndReplaceService/components/FindAndReplaceTool.js +++ b/wax-prosemirror-services/src/FindAndReplaceService/components/FindAndReplaceTool.js @@ -12,6 +12,7 @@ import styled from 'styled-components'; import { grid, override } from '@pubsweet/ui-toolkit'; import { WaxContext, MenuButton } from 'wax-prosemirror-core'; import FindAndReplaceComponent from './FindAndReplaceComponent'; +import epigraphPoetry from '../../TrackChangeService/schema/trackChangesNodes/epigraphPoetryTrackNode'; const Wrapper = styled.div` font-size: 0; @@ -30,6 +31,7 @@ const DropWrapper = styled.div` const FindAndReplaceTool = ({ item }) => { const { t, i18n } = useTranslation(); const { + activeView, pmViews: { main }, } = useContext(WaxContext); @@ -77,8 +79,10 @@ const FindAndReplaceTool = ({ item }) => { active={isOpen} disabled={false} iconName={icon} - onMouseDown={() => { + onMouseDown={e => { + e.preventDefault(); setIsOpen(!isOpen); + activeView.focus(); }} title={ !isEmpty(i18n) && i18n.exists(`Wax.FindAndReplace.${title}`) @@ -92,6 +96,7 @@ const FindAndReplaceTool = ({ item }) => { <FindAndReplaceComponent close={() => { setIsOpen(false); + activeView.focus(); }} /> </DropWrapper> diff --git a/wax-prosemirror-services/src/LinkService/components/LinkComponent.js b/wax-prosemirror-services/src/LinkService/components/LinkComponent.js index 0efda11294af82505a487859682005f20cc7b8f2..0fda433f932491259469a07a2b8a53844f396cc9 100644 --- a/wax-prosemirror-services/src/LinkService/components/LinkComponent.js +++ b/wax-prosemirror-services/src/LinkService/components/LinkComponent.js @@ -90,7 +90,7 @@ const LinkComponent = ({ mark }) => { mark.to, schemaLinkMark.create({ ...((mark && mark.attrs) || {}), - href: linkHref, + href: getValidUrl(linkHref), }), ), ); diff --git a/wax-prosemirror-services/src/SpecialCharactersService/components/SpecialCharactersTool.js b/wax-prosemirror-services/src/SpecialCharactersService/components/SpecialCharactersTool.js index 04b4299c3f12cdd082f4b062d8e88ca27cc6e79d..6fb440fb5917b43495ff4412d3a4bbb5ea140c97 100644 --- a/wax-prosemirror-services/src/SpecialCharactersService/components/SpecialCharactersTool.js +++ b/wax-prosemirror-services/src/SpecialCharactersService/components/SpecialCharactersTool.js @@ -28,6 +28,7 @@ const DropWrapper = styled.div` const SpecialCharactersTool = ({ item }) => { const { t, i18n } = useTranslation(); const { + activeView, pmViews: { main }, } = useContext(WaxContext); @@ -50,8 +51,10 @@ const SpecialCharactersTool = ({ item }) => { active={isOpen} disabled={isDisabled} iconName={icon} - onMouseDown={() => { + onMouseDown={e => { + e.preventDefault(); setIsOpen(!isOpen); + activeView.focus(); }} title={ !isEmpty(i18n) && i18n.exists(`Wax.SpecialCharacters.${title}`) diff --git a/wax-prosemirror-services/src/TrackChangeService/TrackCommentOptionsToolGroupService/TrackCommentOptions.js b/wax-prosemirror-services/src/TrackChangeService/TrackCommentOptionsToolGroupService/TrackCommentOptions.js index d23611a058ef282321c92e32740250a9fb1bf6d4..f7ec07b8694a9ece9ee9be93b7a03e4f2ba359a6 100644 --- a/wax-prosemirror-services/src/TrackChangeService/TrackCommentOptionsToolGroupService/TrackCommentOptions.js +++ b/wax-prosemirror-services/src/TrackChangeService/TrackCommentOptionsToolGroupService/TrackCommentOptions.js @@ -4,7 +4,7 @@ import { injectable, inject } from 'inversify'; import { isEmpty } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { ToolGroup } from 'wax-prosemirror-core'; -import TrackChangeOptionsTool from '../../TrackOptionsService/components/TrackChangeOptionsTool'; +import TrackChangeOptionsTool from '../components/TrackChangeOptionsTool'; @injectable() class TrackCommentOptions extends ToolGroup { diff --git a/wax-prosemirror-services/src/TrackOptionsService/components/TrackChangeOptionsComponent.js b/wax-prosemirror-services/src/TrackChangeService/components/TrackChangeOptionsComponent.js similarity index 100% rename from wax-prosemirror-services/src/TrackOptionsService/components/TrackChangeOptionsComponent.js rename to wax-prosemirror-services/src/TrackChangeService/components/TrackChangeOptionsComponent.js diff --git a/wax-prosemirror-services/src/TrackOptionsService/components/TrackChangeOptionsTool.js b/wax-prosemirror-services/src/TrackChangeService/components/TrackChangeOptionsTool.js similarity index 100% rename from wax-prosemirror-services/src/TrackOptionsService/components/TrackChangeOptionsTool.js rename to wax-prosemirror-services/src/TrackChangeService/components/TrackChangeOptionsTool.js diff --git a/wax-prosemirror-services/src/TrackOptionsService/TrackOptionsService.js b/wax-prosemirror-services/src/TrackOptionsService/TrackOptionsService.js deleted file mode 100644 index 5cd8aa7826a3dc398242856e587af580021eb72e..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrackOptionsService/TrackOptionsService.js +++ /dev/null @@ -1,11 +0,0 @@ -import { Service } from 'wax-prosemirror-core'; -import TrackOptionsTool from './TrackOptionsTool'; - -class TrackOptionsService extends Service { - name = 'TrackOptionsService'; - - register() { - this.container.bind('TrackOptionsTool').to(TrackOptionsTool); - } -} -export default TrackOptionsService; diff --git a/wax-prosemirror-services/src/TrackOptionsService/TrackOptionsTool.js b/wax-prosemirror-services/src/TrackOptionsService/TrackOptionsTool.js deleted file mode 100644 index 24078a5a01f2fda7ca5a2b601fdc767f8ee48e64..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/TrackOptionsService/TrackOptionsTool.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { isEmpty } from 'lodash'; -import { v4 as uuidv4 } from 'uuid'; -import { injectable } from 'inversify'; -import { Tools } from 'wax-prosemirror-core'; -import TrackChangeOptionsTool from './components/TrackChangeOptionsTool'; - -@injectable() -export default class SpecialCharacters extends Tools { - title = 'Track Changes Options'; - icon = 'more'; - name = 'trackchangeoptions'; - - get enable() { - return () => { - return true; - }; - } - - renderTool(view) { - if (isEmpty(view)) return null; - - return this.isDisplayed() ? ( - <TrackChangeOptionsTool item={this.toJSON()} key={uuidv4()} view={view} /> - ) : null; - } -} diff --git a/wax-questions-service/src/EssayService/EssayQuestion.js b/wax-questions-service/src/EssayService/EssayQuestion.js index 80aab753ea3ff45fa40a40d4f24d18cbb6eef649..9438809458de866bf9f37e206625dae227a788dd 100644 --- a/wax-questions-service/src/EssayService/EssayQuestion.js +++ b/wax-questions-service/src/EssayService/EssayQuestion.js @@ -6,22 +6,9 @@ import { Fragment } from 'prosemirror-model'; import { TextSelection } from 'prosemirror-state'; import { findWrapping } from 'prosemirror-transform'; import { Commands, Tools } from 'wax-prosemirror-core'; +import helpers from '../MultipleChoiceQuestionService/helpers/helpers'; import ToolBarBtn from './components/ToolBarBtn'; -const checkifEmpty = view => { - const { state } = view; - const { from, to } = state.selection; - state.doc.nodesBetween(from, to, node => { - if (node.textContent !== ' ') Commands.simulateKey(view, 13, 'Enter'); - }); - if (state.selection.constructor.name === 'GapCursor') { - Commands.simulateKey(view, 13, 'Enter'); - setTimeout(() => { - view.focus(); - }); - } -}; - const createEmptyParagraph = (context, newAnswerId) => { const { pmViews } = context; @@ -63,16 +50,16 @@ class EssayQuestion extends Tools { get run() { return (main, context) => { - checkifEmpty(main); + helpers.checkifEmpty(main); const { state, dispatch } = main; /* Create Wrapping */ const { $from, $to } = state.selection; const range = $from.blockRange($to); - const { tr } = main.state; + const { tr } = state; const wrapping = range && - findWrapping(range, main.state.config.schema.nodes.essay_container, { + findWrapping(range, state.config.schema.nodes.essay_container, { id: uuidv4(), }); if (!wrapping) return false; @@ -86,16 +73,16 @@ class EssayQuestion extends Tools { tr.setSelection(TextSelection.create(tr.doc, range.$to.pos)); - const essayQuestion = main.state.config.schema.nodes.essay_question.create( + const essayQuestion = state.config.schema.nodes.essay_question.create( { id: uuidv4() }, Fragment.empty, ); - const essayPrompt = main.state.config.schema.nodes.essay_prompt.create( + const essayPrompt = state.config.schema.nodes.essay_prompt.create( { id: uuidv4() }, Fragment.empty, ); - const essayAnswer = main.state.config.schema.nodes.essay_answer.create( + const essayAnswer = state.config.schema.nodes.essay_answer.create( { id: uuidv4() }, Fragment.empty, ); diff --git a/wax-questions-service/src/MatchingService/MatchingQuestion.js b/wax-questions-service/src/MatchingService/MatchingQuestion.js index 57a60d7f828542808683b0c68dda6f0cdbd43e90..c0f6055320739bcd1491e1eb7cb03392e096c9d0 100644 --- a/wax-questions-service/src/MatchingService/MatchingQuestion.js +++ b/wax-questions-service/src/MatchingService/MatchingQuestion.js @@ -30,13 +30,13 @@ class MatchingQuestion extends Tools { if (!wrapping) return false; tr.wrap(range, wrapping); - const map = tr.mapping.maps[0]; - let newPos = 0; - map.forEach((_from, _to, _newFrom, newTo) => { - newPos = newTo; - }); + // const map = tr.mapping.maps[0]; + // let newPos = 0; + // map.forEach((_from, _to, _newFrom, newTo) => { + // newPos = newTo; + // }); - tr.setSelection(TextSelection.create(tr.doc, range.$to.pos)); + tr.setSelection(TextSelection.create(tr.doc, range.$to.pos + 1)); const option = state.config.schema.nodes.matching_option.create( { id: uuidv4(), isfirst: true }, Fragment.empty, diff --git a/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js b/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js index 06e1ef7818728bf130e901b3f74a11104b203ead..ef075cfc1e1bf3f0cbf69a1dbc17ec7769a8033a 100644 --- a/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js +++ b/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceQuestionService.js @@ -5,6 +5,7 @@ import multipleChoiceContainerNode from './schema/multipleChoiceContainerNode'; import questionNode from './schema/questionNode'; import AnswerComponent from './components/AnswerComponent'; import QuestionComponent from './components/QuestionComponent'; +import MultipleChoiceContainerComponent from './components/MultipleChoiceContainerComponent'; import MultipleChoiceContainerNodeView from './MultipleChoiceContainerNodeView'; import MultipleChoiceNodeView from './MultipleChoiceNodeView'; import QuestionNodeView from './QuestionNodeView'; @@ -12,16 +13,8 @@ import MultipleChoiceSingleCorrectQuestionService from './MultipleChoiceSingleCo import TrueFalseQuestionService from './TrueFalseQuestionService/TrueFalseQuestionService'; import TrueFalseSingleCorrectQuestionService from './TrueFalseSingleCorrectQuestionService/TrueFalseSingleCorrectQuestionService'; import './multipleQuestionStyles.css'; -import MoveCursorPlugin from './plugins/MoveCursorPlugin'; class MultipleChoiceQuestionService extends Service { - boot() { - // this.app.PmPlugins.add( - // 'moveCursorPlugin', - // MoveCursorPlugin('moveCursorPlugin'), - // ); - } - register() { this.container.bind('MultipleChoiceQuestion').to(MultipleChoiceQuestion); const createNode = this.container.get('CreateNode'); @@ -39,11 +32,11 @@ class MultipleChoiceQuestionService extends Service { question_node_multiple: questionNode, }); - // addPortal({ - // nodeView: MultipleChoiceContainerNodeView, - // component: QuestionComponent, - // context: this.app, - // }); + addPortal({ + nodeView: MultipleChoiceContainerNodeView, + component: MultipleChoiceContainerComponent, + context: this.app, + }); addPortal({ nodeView: QuestionNodeView, diff --git a/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectContainerNodeView.js b/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectContainerNodeView.js index c04f4e6160e4d0a4dd99d3602ec99f77093570bb..d9db3a3fc6ac681c6991a7c3d19f1717ed0acd7a 100644 --- a/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectContainerNodeView.js +++ b/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectContainerNodeView.js @@ -19,11 +19,15 @@ export default class MultipleChoiceSingleCorrectContainerNodeView extends Questi } static name() { - return 'multiple_choice_container'; + return 'multiple_choice_single_correct_container'; } stopEvent(event) { - if (event.target.type === 'text') { + if ( + !event.target.type || + event.target.type === 'button' || + event.target.type === 'text' + ) { return true; } const innerView = this.context.pmViews[this.node.attrs.id]; diff --git a/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestionService.js b/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestionService.js index 2fa789738c2f51dc5aeb8b2dd572e44e7c8a806f..79f481c1babf7c2fbf198c863514af80826ff219 100644 --- a/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestionService.js +++ b/wax-questions-service/src/MultipleChoiceQuestionService/MultipleChoiceSingleCorrectQuestionService/MultipleChoiceSingleCorrectQuestionService.js @@ -4,8 +4,9 @@ import multipleChoiceSingleCorrectNode from './schema/multipleChoiceSingleCorrec import multipleChoiceSingleCorrectContainerNode from './schema/multipleChoiceSingleCorrectContainerNode'; import questionSingleNode from './schema/questionSingleNode'; import AnswerComponent from './components/AnswerComponent'; -import MultipleChoiceSingleCorrectContainerNodeView from './MultipleChoiceSingleCorrectContainerNodeView'; +import MultipleChoiceContainerComponent from '../components/MultipleChoiceContainerComponent'; import MultipleChoiceSingleCorrectNodeView from './MultipleChoiceSingleCorrectNodeView'; +import MultipleChoiceSingleCorrectContainerNodeView from './MultipleChoiceSingleCorrectContainerNodeView'; import QuestionMultipleSingleNodeView from './QuestionMultipleSingleNodeView'; import QuestionComponent from '../components/QuestionComponent'; @@ -29,11 +30,11 @@ class MultipleChoiceSingleCorrectQuestionService extends Service { question_node_multiple_single: questionSingleNode, }); - // addPortal({ - // nodeView: MultipleChoiceSingleCorrectContainerNodeView, - // component: QuestionComponent, - // context: this.app, - // }); + addPortal({ + nodeView: MultipleChoiceSingleCorrectContainerNodeView, + component: MultipleChoiceContainerComponent, + context: this.app, + }); addPortal({ nodeView: QuestionMultipleSingleNodeView, diff --git a/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseQuestionService/TrueFalseQuestionService.js b/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseQuestionService/TrueFalseQuestionService.js index 857e451bb49f4f47cd41c081cefa2d1e234fe611..c90abf2b7c93002dc1189397486bd427f29ac192 100644 --- a/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseQuestionService/TrueFalseQuestionService.js +++ b/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseQuestionService/TrueFalseQuestionService.js @@ -4,6 +4,7 @@ import trueFalseNode from './schema/trueFalseNode'; import questionTrueFalseNode from './schema/questionTrueFalseNode'; import trueFalseContainerNode from './schema/trueFalseContainerNode'; import AnswerComponent from './components/AnswerComponent'; +import MultipleChoiceContainerComponent from '../components/MultipleChoiceContainerComponent'; import TrueFalseContainerNodeView from './TrueFalseContainerNodeView'; import TrueFalseNodeView from './TrueFalseNodeView'; import QuestionTrueFalseNodeView from './QuestionTrueFalseNodeView'; @@ -27,11 +28,11 @@ class TrueFalseQuestionService extends Service { question_node_true_false: questionTrueFalseNode, }); - // addPortal({ - // nodeView: TrueFalseContainerNodeView, - // component: QuestionComponent, - // context: this.app, - // }); + addPortal({ + nodeView: TrueFalseContainerNodeView, + component: MultipleChoiceContainerComponent, + context: this.app, + }); addPortal({ nodeView: QuestionTrueFalseNodeView, diff --git a/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/TrueFalseSingleCorrectQuestionService.js b/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/TrueFalseSingleCorrectQuestionService.js index c63d1f5ddfb828fda79ab56cdf846701262a4df3..12eaf6789ff1086cf74d6d7fa1a9b0eeef869eae 100644 --- a/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/TrueFalseSingleCorrectQuestionService.js +++ b/wax-questions-service/src/MultipleChoiceQuestionService/TrueFalseSingleCorrectQuestionService/TrueFalseSingleCorrectQuestionService.js @@ -3,6 +3,7 @@ import TrueFalseSingleCorrectQuestion from './TrueFalseSingleCorrectQuestion'; import trueFalseSingleCorrectNode from './schema/trueFalseSingleCorrectNode'; import trueFalseSingleCorrectContainerNode from './schema/trueFalseSingleCorrectContainerNode'; import questionTrueFalseSingleNode from './schema/questionTrueFalseSingleNode'; +import MultipleChoiceContainerComponent from '../components/MultipleChoiceContainerComponent'; import AnswerComponent from './components/AnswerComponent'; import TrueFalseSingleCorrectContainerNodeView from './TrueFalseSingleCorrectContainerNodeView'; import TrueFalseSingleCorrectNodeView from './TrueFalseSingleCorrectNodeView'; @@ -29,11 +30,11 @@ class TrueFalseSingleCorrectQuestionService extends Service { true_false_single_correct: trueFalseSingleCorrectNode, }); - // addPortal({ - // nodeView: TrueFalseSingleCorrectContainerNodeView, - // component: QuestionComponent, - // context: this.app, - // }); + addPortal({ + nodeView: TrueFalseSingleCorrectContainerNodeView, + component: MultipleChoiceContainerComponent, + context: this.app, + }); addPortal({ nodeView: QuestionTrueFalseSingleNodeView, diff --git a/wax-questions-service/src/MultipleChoiceQuestionService/components/MultipleChoiceContainerComponent.js b/wax-questions-service/src/MultipleChoiceQuestionService/components/MultipleChoiceContainerComponent.js new file mode 100644 index 0000000000000000000000000000000000000000..e38a6e2b7e2f6c6898e6f9c33fe3f9bf4a390f44 --- /dev/null +++ b/wax-questions-service/src/MultipleChoiceQuestionService/components/MultipleChoiceContainerComponent.js @@ -0,0 +1,109 @@ +import React, { useContext } from 'react'; +import { WaxContext, DocumentHelpers, Icon } from 'wax-prosemirror-core'; +import styled from 'styled-components'; +import ContainerEditor from '../../FillTheGapQuestionService/components/ContainerEditor'; + +const MultipleChoiceQuestionWrapper = styled.div` + border: 3px solid #f5f5f7; + margin: 0px 38px 15px 38px; + margin-top: 10px; +`; +const MultipleChoiceContainerTool = styled.div` + border-bottom: 3px solid #f5f5f7; + height: 32px; +`; + +const ActionButton = styled.button` + background: transparent; + cursor: pointer; + margin-top: 16px; + border: none; + position: relative; + bottom: 14px; + left: 6px; + float: right; +`; + +const StyledIconActionRemove = styled(Icon)` + height: 24px; + width: 24px; +`; + +const MultipleChoiceQuestionContainer = styled.div` + // border: 3px solid #f5f5f7; + margin-bottom: 30px; +`; + +export default ({ node, view, getPos }) => { + const context = useContext(WaxContext); + const { + pmViews: { main }, + } = context; + + const customProps = main.props.customValues; + const { testMode } = customProps; + + const isEditable = main.props.editable(editable => { + return editable; + }); + + const readOnly = !isEditable; + + const removeQuestion = () => { + const allNodes = getNodes(context.pmViews.main); + + allNodes.forEach(singleNode => { + if (singleNode.node.attrs.id === node.attrs.id) { + context.pmViews.main.dispatch( + context.pmViews.main.state.tr.delete( + singleNode.pos, + singleNode.pos + singleNode.node.nodeSize, + ), + ); + } + }); + }; + + return ( + <MultipleChoiceQuestionWrapper> + <div> + {!testMode && !readOnly && ( + <MultipleChoiceContainerTool> + <ActionButton + aria-label="delete this question" + onClick={removeQuestion} + type="button" + > + <StyledIconActionRemove name="deleteOutlinedQuestion" /> + </ActionButton> + </MultipleChoiceContainerTool> + )} + </div> + <MultipleChoiceQuestionContainer className="multiple-choice"> + <ContainerEditor + disallowedTools={['MultipleChoice']} + getPos={getPos} + isNotEditable + node={node} + view={view} + /> + </MultipleChoiceQuestionContainer> + </MultipleChoiceQuestionWrapper> + ); +}; + +const getNodes = view => { + const allNodes = DocumentHelpers.findBlockNodes(view.state.doc); + const fillTheGapContainerNodes = []; + allNodes.forEach(node => { + if ( + node.node.type.name === 'multiple_choice_container' || + node.node.type.name === 'multiple_choice_single_correct_container' || + node.node.type.name === 'true_false_container' || + node.node.type.name === 'true_false_single_correct_container' + ) { + fillTheGapContainerNodes.push(node); + } + }); + return fillTheGapContainerNodes; +}; diff --git a/wax-questions-service/src/MultipleChoiceQuestionService/multipleQuestionStyles.css b/wax-questions-service/src/MultipleChoiceQuestionService/multipleQuestionStyles.css index f35d630133fada470ad4809d2d207459caf3ac0c..4fa9fb66638c89a58d6c379817464cf494eb3b2c 100644 --- a/wax-questions-service/src/MultipleChoiceQuestionService/multipleQuestionStyles.css +++ b/wax-questions-service/src/MultipleChoiceQuestionService/multipleQuestionStyles.css @@ -4,10 +4,10 @@ .multiple-choice-single-correct, .true-false, .true-false-single-correct { - border: 3px solid #f5f5f7; + /* border: 3px solid #f5f5f7; + padding: 20px; */ counter-reset: question-item-multiple; - margin: 38px; - padding: 20px; + margin: 12px 2px 12px 12px; padding-top: 0px; } @@ -28,23 +28,6 @@ padding: 5px 5px 0 5px; } - -/* .multiple-choice:before { - content: 'Multiple Choice' ; -} - -.multiple-choice-single-correct:before { - content: 'Multiple Choice Single Correct'; - } - -.true-false:before { - content: 'True False'; -} - -.true-false-single-correct:before { - content: 'True False Single Correct'; -} */ - .rc-switch { position: relative; display: inline-block; diff --git a/wax-table-service/src/components/CreateTable.js b/wax-table-service/src/components/CreateTable.js index 8af593bc37f662d8d938963ea4a066b97855722f..9a76200fba8091b35bba727e4e2d7d83fdc3784e 100644 --- a/wax-table-service/src/components/CreateTable.js +++ b/wax-table-service/src/components/CreateTable.js @@ -65,8 +65,10 @@ const CreateTable = ({ item }) => { active={isOpen} disabled={isDisabled} iconName={icon} - onMouseDown={() => { + onMouseDown={e => { + e.preventDefault(); setIsOpen(!isOpen); + activeView.focus(); }} title={ !isEmpty(i18n) && i18n.exists(`Wax.Tables.${title}`) diff --git a/wax-table-service/src/tableSrc/index.js b/wax-table-service/src/tableSrc/index.js index d81747469ab8641c2d744c0945b887aa8d98b163..4805837f6d42004f864ab3945c7baffcbb05e31e 100644 --- a/wax-table-service/src/tableSrc/index.js +++ b/wax-table-service/src/tableSrc/index.js @@ -1598,7 +1598,7 @@ function insertCells(state, dispatch, tableStart, rect, cells) { var handleKeyDown = keydownHandler({ ArrowLeft: arrow('horiz', -1), ArrowRight: arrow('horiz', 1), - ArrowUp: arrow('vert', -1), + // ArrowUp: arrow('vert', -1), ArrowDown: arrow('vert', 1), Tab: tabulation(1), 'Shift-Tab': tabulation(-1),