diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/EditorComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/EditorComponent.js index 7ed8665c37d64f6e3584c105c087e5607c42aa89..4fef337a14e9e75e64af6f75262c864634faab03 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/EditorComponent.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/EditorComponent.js @@ -1,12 +1,17 @@ import React, { useContext, useRef, useEffect } from 'react'; import styled from 'styled-components'; import { EditorView } from 'prosemirror-view'; -import { EditorState, TextSelection } from 'prosemirror-state'; +import { EditorState, TextSelection, NodeSelection } from 'prosemirror-state'; import { StepMap } from 'prosemirror-transform'; import { keymap } from 'prosemirror-keymap'; -import { baseKeymap } from 'prosemirror-commands'; +import { baseKeymap, chainCommands } from 'prosemirror-commands'; import { undo, redo } from 'prosemirror-history'; import { WaxContext, ComponentPlugin } from 'wax-prosemirror-core'; +import { + splitListItem, + liftListItem, + sinkListItem, +} from 'prosemirror-schema-list'; import Placeholder from '../plugins/placeholder'; import FakeCursorPlugin from '../../MultipleDropDownService/plugins/FakeCursorPlugin'; @@ -26,7 +31,7 @@ const EditorWrapper = styled.div` } :empty::before { - content: 'Type your answer'; + content: 'Type your question'; color: #aaa; float: left; font-style: italic; @@ -50,9 +55,10 @@ const EditorWrapper = styled.div` } } `; + let WaxOverlays = () => true; -const EditorComponent = ({ node, view, getPos }) => { +const QuestionEditorComponent = ({ node, view, getPos }) => { const editorRef = useRef(); const context = useContext(WaxContext); @@ -71,15 +77,46 @@ const EditorComponent = ({ node, view, getPos }) => { const createKeyBindings = () => { const keys = getKeys(); Object.keys(baseKeymap).forEach(key => { - keys[key] = baseKeymap[key]; + if (keys[key]) { + keys[key] = chainCommands(keys[key], baseKeymap[key]); + } else { + keys[key] = baseKeymap[key]; + } }); return keys; }; + const pressEnter = (state, dispatch) => { + if (state.selection.node && state.selection.node.type.name === 'image') { + const { $from, to } = state.selection; + + const same = $from.sharedDepth(to); + + const pos = $from.before(same); + dispatch(state.tr.setSelection(NodeSelection.create(state.doc, pos))); + return true; + } + // LISTS + if (splitListItem(state.schema.nodes.list_item)(state)) { + splitListItem(state.schema.nodes.list_item)(state, dispatch); + return true; + } + + return false; + }; + const getKeys = () => { return { 'Mod-z': () => undo(view.state, view.dispatch), 'Mod-y': () => redo(view.state, view.dispatch), + 'Mod-[': liftListItem(view.state.schema.nodes.list_item), + 'Mod-]': sinkListItem(view.state.schema.nodes.list_item), + // Enter: () => + // splitListItem(questionView.state.schema.nodes.list_item)( + // questionView.state, + // questionView.dispatch, + // ), + Enter: pressEnter, }; }; @@ -92,7 +129,7 @@ const EditorComponent = ({ node, view, getPos }) => { }; finalPlugins = finalPlugins.concat([ - createPlaceholder('Type your answer'), + createPlaceholder('Type your question'), ...plugins, ]); @@ -109,16 +146,19 @@ const EditorComponent = ({ node, view, getPos }) => { plugins: finalPlugins, }), dispatchTransaction, - disallowedTools: ['Lists', 'lift', 'MultipleChoice'], + disallowedTools: ['MultipleChoice'], handleDOMEvents: { mousedown: () => { + context.updateView({}, questionId); main.dispatch( main.state.tr .setMeta('outsideView', questionId) .setSelection( new TextSelection( main.state.tr.doc.resolve( - getPos() + context.pmViews[questionId].state.selection.to, + getPos() + + 1 + + context.pmViews[questionId].state.selection.to, ), ), ), @@ -131,7 +171,9 @@ const EditorComponent = ({ node, view, getPos }) => { // ), // ), // ); + context.updateView({}, questionId); + if (questionView.hasFocus()) questionView.focus(); }, blur: (editorView, event) => { @@ -183,4 +225,4 @@ const EditorComponent = ({ node, view, getPos }) => { ); }; -export default EditorComponent; +export default QuestionEditorComponent; diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/QuestionComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/QuestionComponent.js index 90c2772b1721a19247b2e98e4b7ee9c099ed1c0a..0f5e0f3039f51aeb09b8c3f038f4a9fb84068de5 100644 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/QuestionComponent.js +++ b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/QuestionComponent.js @@ -1,6 +1,6 @@ import React from 'react'; -import QuestionEditorComponent from './QuestionEditorComponent'; +import EditorComponent from './EditorComponent'; export default ({ node, view, getPos }) => { - return <QuestionEditorComponent getPos={getPos} node={node} view={view} />; + return <EditorComponent getPos={getPos} node={node} view={view} />; }; diff --git a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/QuestionEditorComponent.js b/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/QuestionEditorComponent.js deleted file mode 100644 index 2e79dfc2e2f5e440a3164ca86590e90376f6a61b..0000000000000000000000000000000000000000 --- a/wax-prosemirror-services/src/MultipleChoiceQuestionService/components/QuestionEditorComponent.js +++ /dev/null @@ -1,219 +0,0 @@ -import React, { useContext, useRef, useEffect } from 'react'; -import styled from 'styled-components'; -import { EditorView } from 'prosemirror-view'; -import { EditorState, TextSelection, NodeSelection } from 'prosemirror-state'; -import { StepMap } from 'prosemirror-transform'; -import { keymap } from 'prosemirror-keymap'; -import { baseKeymap, chainCommands } from 'prosemirror-commands'; -import { undo, redo } from 'prosemirror-history'; -import { WaxContext, ComponentPlugin } from 'wax-prosemirror-core'; -import { - splitListItem, - liftListItem, - sinkListItem, -} from 'prosemirror-schema-list'; -import Placeholder from '../plugins/placeholder'; -import FakeCursorPlugin from '../../MultipleDropDownService/plugins/FakeCursorPlugin'; - -const EditorWrapper = styled.div` - border: none; - display: flex; - flex: 2 1 auto; - justify-content: left; - - .ProseMirror { - white-space: break-spaces; - width: 100%; - word-wrap: break-word; - - &:focus { - outline: none; - } - - :empty::before { - content: 'Type your question'; - color: #aaa; - float: left; - font-style: italic; - pointer-events: none; - } - - p:first-child { - margin: 0; - } - - p.empty-node:first-child::before { - content: attr(data-content); - } - - .empty-node::before { - color: rgb(170, 170, 170); - float: left; - font-style: italic; - height: 0px; - pointer-events: none; - } - } -`; - -let WaxOverlays = () => true; - -const QuestionEditorComponent = ({ node, view, getPos }) => { - const editorRef = useRef(); - - const context = useContext(WaxContext); - const { - app, - pmViews: { main }, - } = context; - let questionView; - const questionId = node.attrs.id; - const isEditable = main.props.editable(editable => { - return editable; - }); - - let finalPlugins = [FakeCursorPlugin()]; - - const createKeyBindings = () => { - const keys = getKeys(); - Object.keys(baseKeymap).forEach(key => { - if (keys[key]) { - keys[key] = chainCommands(keys[key], baseKeymap[key]); - } else { - keys[key] = baseKeymap[key]; - } - }); - return keys; - }; - - const pressEnter = (state, dispatch) => { - if (state.selection.node && state.selection.node.type.name === 'image') { - const { $from, to } = state.selection; - - const same = $from.sharedDepth(to); - - const pos = $from.before(same); - dispatch(state.tr.setSelection(NodeSelection.create(state.doc, pos))); - return true; - } - // LISTS - if (splitListItem(state.schema.nodes.list_item)(state)) { - splitListItem(state.schema.nodes.list_item)(state, dispatch); - return true; - } - - return false; - }; - - const getKeys = () => { - return { - 'Mod-z': () => undo(view.state, view.dispatch), - 'Mod-y': () => redo(view.state, view.dispatch), - 'Mod-[': liftListItem(view.state.schema.nodes.list_item), - 'Mod-]': sinkListItem(view.state.schema.nodes.list_item), - // Enter: () => - // splitListItem(questionView.state.schema.nodes.list_item)( - // questionView.state, - // questionView.dispatch, - // ), - Enter: pressEnter, - }; - }; - - const plugins = [keymap(createKeyBindings()), ...app.getPlugins()]; - - const createPlaceholder = placeholder => { - return Placeholder({ - content: placeholder, - }); - }; - - finalPlugins = finalPlugins.concat([ - createPlaceholder('Type your question'), - ...plugins, - ]); - - useEffect(() => { - WaxOverlays = ComponentPlugin('waxOverlays'); - questionView = new EditorView( - { - mount: editorRef.current, - }, - { - editable: () => isEditable, - state: EditorState.create({ - doc: node, - plugins: finalPlugins, - }), - dispatchTransaction, - disallowedTools: ['MultipleChoice'], - handleDOMEvents: { - mousedown: () => { - context.updateView({}, questionId); - main.dispatch( - main.state.tr - .setMeta('outsideView', questionId) - .setSelection( - new TextSelection( - main.state.tr.doc.resolve( - getPos() + - 1 + - context.pmViews[questionId].state.selection.to, - ), - ), - ), - ); - context.updateView({}, questionId); - - if (questionView.hasFocus()) questionView.focus(); - }, - blur: (editorView, event) => { - if (questionView && event.relatedTarget === null) { - questionView.focus(); - } - }, - }, - - attributes: { - spellcheck: 'false', - }, - }, - ); - - // Set Each note into Wax's Context - context.updateView( - { - [questionId]: questionView, - }, - questionId, - ); - if (questionView.hasFocus()) questionView.focus(); - }, []); - - const dispatchTransaction = tr => { - const { state, transactions } = questionView.state.applyTransaction(tr); - questionView.updateState(state); - context.updateView({}, questionId); - - if (!tr.getMeta('fromOutside')) { - const outerTr = view.state.tr; - const offsetMap = StepMap.offset(getPos() + 1); - for (let i = 0; i < transactions.length; i++) { - const { steps } = transactions[i]; - for (let j = 0; j < steps.length; j++) - outerTr.step(steps[j].map(offsetMap)); - } - if (outerTr.docChanged) - view.dispatch(outerTr.setMeta('outsideView', questionId)); - } - }; - - return ( - <EditorWrapper> - <div ref={editorRef} /> - <WaxOverlays activeViewId={questionId} /> - </EditorWrapper> - ); -}; - -export default QuestionEditorComponent;