Skip to content

Commit

Permalink
Merge pull request #552 from cofacts/collab-line-break
Browse files Browse the repository at this point in the history
Fix collab editor line break disappear issue
  • Loading branch information
MrOrz authored Oct 25, 2023
2 parents 2b90d06 + c39cc79 commit 53690ec
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 440 deletions.
8 changes: 6 additions & 2 deletions components/Collaborate/CollabEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { Button, Typography } from '@material-ui/core';
import { TranscribePenIcon } from 'components/icons';
import { useProseMirror, ProseMirror } from 'use-prosemirror';
import { schema } from './Schema';
import { exampleSetup } from 'prosemirror-example-setup';
import { keymap } from 'prosemirror-keymap';
import { useState, useRef, useEffect } from 'react';
import { makeStyles } from '@material-ui/core/styles';
Expand Down Expand Up @@ -112,9 +111,14 @@ const Editor = ({ provider, currentUser, className, innerRef, onUnmount }) => {
'Mod-z': undo,
'Mod-y': redo,
'Mod-Shift-z': redo,
Enter: (state, dispatch) => {
// Insert \n on enter
dispatch(state.tr.insertText('\n').scrollIntoView());
return true;
},
}),
PlaceholderPlugin(t`Input transcript`),
].concat(exampleSetup({ schema, menuBar: false })),
],
});

return (
Expand Down
3 changes: 1 addition & 2 deletions components/Collaborate/CollabHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as Y from 'yjs';
import { ySyncPlugin, ySyncPluginKey } from 'y-prosemirror';
import { useProseMirror, ProseMirror } from 'use-prosemirror';
import { schema } from './Schema';
import { exampleSetup } from 'prosemirror-example-setup';
import { useState, useRef, useEffect, forwardRef, useCallback } from 'react';
import { Button, Modal, Box, Typography } from '@material-ui/core';
import { ToggleButtonGroup, ToggleButton } from '@material-ui/lab';
Expand Down Expand Up @@ -172,7 +171,7 @@ const CustomModalContent = forwardRef(function CustomModalContent(
permanentUserData,
onFirstRender,
}),
].concat(exampleSetup({ schema, menuBar: false })),
],
});

return (
Expand Down
33 changes: 0 additions & 33 deletions components/Collaborate/Prosemirror.css
Original file line number Diff line number Diff line change
Expand Up @@ -68,29 +68,6 @@ li.ProseMirror-selectednode:after {
.ProseMirror-focused .ProseMirror-gapcursor {
display: block;
}
/* Add space around the hr to make clicking it easier */

.ProseMirror-example-setup-style hr {
padding: 2px 10px;
border: none;
margin: 1em 0;
}

.ProseMirror-example-setup-style hr:after {
content: "";
display: block;
height: 1px;
background-color: silver;
line-height: 2px;
}

.ProseMirror ul, .ProseMirror ol {
padding-left: 30px;
}

.ProseMirror-example-setup-style img {
cursor: default;
}

.ProseMirror-prompt {
background: white;
Expand Down Expand Up @@ -134,16 +111,6 @@ li.ProseMirror-selectednode:after {
display: none;
}

.ProseMirror p:first-child,
.ProseMirror h1:first-child,
.ProseMirror h2:first-child,
.ProseMirror h3:first-child,
.ProseMirror h4:first-child,
.ProseMirror h5:first-child,
.ProseMirror h6:first-child {
margin-top: 10px;
}

.ProseMirror {
padding: 4px 8px 4px 14px;
line-height: 1.2;
Expand Down
209 changes: 4 additions & 205 deletions components/Collaborate/Schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
//
import { Schema } from 'prosemirror-model';

const brDOM = ['br'];

const calcYChangeStyle = ychange => {
switch (ychange.type) {
case 'removed':
Expand Down Expand Up @@ -63,15 +61,13 @@ const hoverWrapper = (ychange, els) => {
export const nodes = {
// :: NodeSpec The top level document node.
doc: {
content: 'block+',
content: 'paragraph+',
},

// :: NodeSpec A plain paragraph textblock. Represented in the DOM
// as a `<p>` element.
paragraph: {
attrs: { ychange: { default: null } },
content: 'inline*',
group: 'block',
content: 'text*',
code: true,
parseDOM: [{ tag: 'p' }],
toDOM(node) {
// only render changes if no child nodes
Expand All @@ -87,209 +83,12 @@ export const nodes = {
},
},

// :: NodeSpec A blockquote (`<blockquote>`) wrapping one or more blocks.
blockquote: {
attrs: { ychange: { default: null } },
content: 'block+',
group: 'block',
defining: true,
parseDOM: [{ tag: 'blockquote' }],
toDOM(node) {
return [
'blockquote',
calcYchangeDomAttrs(node.attrs),
...hoverWrapper(node.attrs.ychange, [0]),
];
},
},

// :: NodeSpec A horizontal rule (`<hr>`).
horizontal_rule: {
attrs: { ychange: { default: null } },
group: 'block',
parseDOM: [{ tag: 'hr' }],
toDOM(node) {
return [
'hr',
calcYchangeDomAttrs(node.attrs),
...hoverWrapper(node.attrs.ychange, []),
];
},
},

// :: NodeSpec A heading textblock, with a `level` attribute that
// should hold the number 1 to 6. Parsed and serialized as `<h1>` to
// `<h6>` elements.
heading: {
attrs: {
level: { default: 1 },
ychange: { default: null },
},
content: 'inline*',
group: 'block',
defining: true,
parseDOM: [
{ tag: 'h1', attrs: { level: 1 } },
{ tag: 'h2', attrs: { level: 2 } },
{ tag: 'h3', attrs: { level: 3 } },
{ tag: 'h4', attrs: { level: 4 } },
{ tag: 'h5', attrs: { level: 5 } },
{ tag: 'h6', attrs: { level: 6 } },
],
toDOM(node) {
return [
'h' + node.attrs.level,
calcYchangeDomAttrs(node.attrs),
...hoverWrapper(node.attrs.ychange, [0]),
];
},
},

// :: NodeSpec A code listing. Disallows marks or non-text inline
// nodes by default. Represented as a `<pre>` element with a
// `<code>` element inside of it.
code_block: {
attrs: { ychange: { default: null } },
content: 'text*',
marks: '',
group: 'block',
code: true,
defining: true,
parseDOM: [{ tag: 'pre', preserveWhitespace: 'full' }],
toDOM(node) {
return [
'pre',
calcYchangeDomAttrs(node.attrs),
...hoverWrapper(node.attrs.ychange, [['code', 0]]),
];
},
},

// :: NodeSpec The text node.
text: {
group: 'inline',
},

// :: NodeSpec An inline image (`<img>`) node. Supports `src`,
// `alt`, and `href` attributes. The latter two default to the empty
// string.
image: {
inline: true,
attrs: {
ychange: { default: null },
src: {},
alt: { default: null },
title: { default: null },
},
group: 'inline',
draggable: true,
parseDOM: [
{
tag: 'img[src]',
getAttrs(dom) {
return {
src: dom.getAttribute('src'),
title: dom.getAttribute('title'),
alt: dom.getAttribute('alt'),
};
},
},
],
toDOM(node) {
const domAttrs = {
src: node.attrs.src,
title: node.attrs.title,
alt: node.attrs.alt,
};
return [
'img',
calcYchangeDomAttrs(node.attrs, domAttrs),
...hoverWrapper(node.attrs.ychange, []),
];
},
},

// :: NodeSpec A hard line break, represented in the DOM as `<br>`.
hard_break: {
inline: true,
group: 'inline',
selectable: false,
parseDOM: [{ tag: 'br' }],
toDOM() {
return brDOM;
},
},
text: {},
};

const emDOM = ['em', 0];
const strongDOM = ['strong', 0];
const codeDOM = ['code', 0];

// :: Object [Specs](#model.MarkSpec) for the marks in the schema.
export const marks = {
// :: MarkSpec A link. Has `href` and `title` attributes. `title`
// defaults to the empty string. Rendered and parsed as an `<a>`
// element.
link: {
attrs: {
href: {},
title: { default: null },
},
inclusive: false,
parseDOM: [
{
tag: 'a[href]',
getAttrs(dom) {
return {
href: dom.getAttribute('href'),
title: dom.getAttribute('title'),
};
},
},
],
toDOM(node) {
return ['a', node.attrs, 0];
},
},

// :: MarkSpec An emphasis mark. Rendered as an `<em>` element.
// Has parse rules that also match `<i>` and `font-style: italic`.
em: {
parseDOM: [{ tag: 'i' }, { tag: 'em' }, { style: 'font-style=italic' }],
toDOM() {
return emDOM;
},
},

// :: MarkSpec A strong mark. Rendered as `<strong>`, parse rules
// also match `<b>` and `font-weight: bold`.
strong: {
parseDOM: [
{ tag: 'strong' },
// This works around a Google Docs misbehavior where
// pasted content will be inexplicably wrapped in `<b>`
// tags with a font-weight normal.
{
tag: 'b',
getAttrs: node => node.style.fontWeight !== 'normal' && null,
},
{
style: 'font-weight',
getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null,
},
],
toDOM() {
return strongDOM;
},
},

// :: MarkSpec Code font mark. Represented as a `<code>` element.
code: {
parseDOM: [{ tag: 'code' }],
toDOM() {
return codeDOM;
},
},
ychange: {
attrs: {
user: { default: null },
Expand Down
Loading

0 comments on commit 53690ec

Please sign in to comment.