Commit e8c7c7fb authored by Giannis Kopanas's avatar Giannis Kopanas

fix(editor): change loading of main editor

parent ef6f9271
......@@ -112,6 +112,14 @@ class Editoria extends Component {
placeholder="Type Something..."
theme="editoria"
layout="editoria"
fileUpload={file => {
let reader = new FileReader()
return new Promise((accept, fail) => {
reader.onload = () => accept(reader.result)
reader.onerror = () => fail(reader.error)
// Some extra delay to make the asynchronicity visible
setTimeout(() => reader.readAsDataURL(file), 1500)
})}}
value="<p>hello</p>
<ul><li>listItem 1</li><li>listItem 2</li><li>listItem 3</li></ul>
<table>
......@@ -119,19 +127,30 @@ class Editoria extends Component {
<tr><td>Jill</td><td>Smith</td><td>50</td></tr>
<tr><td>Eve</td><td>Jackson</td><td>94</td></tr>
</table>"
renderLayout={({ editor, ...props }) => (
>
{({ editor, view, ...props }) => (
<React.Fragment>
<MainMenuBar {...props} />
<MainMenuBar view={view} {...props} />
<div className="wax-surface-container">
<SideMenuBar {...props} />
<SideMenuBar view={view} {...props} />
{editor}
</div>
</React.Fragment>
)}
/>
</StyledWax>
</React.Fragment>
);
}
}
/*
<p>hello</p>
<ul><li>listItem 1</li><li>listItem 2</li><li>listItem 3</li></ul>
<table>
<tr> <th>Firstname</th> <th>Lastname</th> <th>Age</th></tr>
<tr><td>Jill</td><td>Smith</td><td>50</td></tr>
<tr><td>Eve</td><td>Jackson</td><td>94</td></tr>
</table>
*/
export default Editoria;
......@@ -13,7 +13,7 @@ const UploadImage = styled.div`
display: none;
}
`;
const ImageUpload = ({ item, state, handle, fileUpload }) => (
const ImageUpload = ({ item, view: { state }, handle, fileUpload }) => (
<UploadImage>
<label
className="custom-file-upload"
......
......@@ -32,7 +32,7 @@ const dropDownOptions = [
{ label: "Toggle header cells", value: "toggleHeaderCell" }
];
const TableDropDown = ({ dispatch, state, item }) => (
const TableDropDown = ({ view: { dispatch, state }, item }) => (
<DropdownStyled
options={dropDownOptions}
onChange={option => {
......
......@@ -8,20 +8,20 @@ const ButtonStyled = styled.button`
pointer-events: ${props => (props.select ? "default" : "none")};
`;
const Button = ({ dispatch, state, item }) => (
const Button = ({ view = {}, item }) => (
<ButtonStyled
type="button"
className={classnames({
[classes.button]: true,
[classes.active]: item.active && item.active(state)
[classes.active]: item.active && item.active(view.state)
})}
title={item.title}
disabled={item.enable && !item.enable(state)}
disabled={item.enable && !item.enable(view.state)}
onMouseDown={e => {
e.preventDefault();
item.run(state, dispatch);
item.run(view.state, view.dispatch);
}}
select={item.select && item.select(state)}
select={item.select && item.select(view.state)}
>
{item.content}
</ButtonStyled>
......
......@@ -24,8 +24,7 @@ const setMenuItems = (menu, menuItems) => {
const MainMenuBar = ({
menuItems = [],
children,
state,
dispatch,
view,
className,
fileUpload
}) => (
......@@ -35,7 +34,7 @@ const MainMenuBar = ({
{
<span className={classes.group}>
{map(setMenuItems(MainMenuBarItems, menuItems), item =>
item.menu({ state, dispatch, item, fileUpload })
item.menu({ view, item, fileUpload })
)}
</span>
}
......
......@@ -71,7 +71,7 @@ export default {
enable: undo,
run: undo,
select: state => true,
menu: props => <Button key={uuid()} {...props} />
menu: props => <Button key={uuid()} {...props} />
},
redo: {
title: "Redo last undone change",
......
......@@ -23,8 +23,7 @@ const setMenuItems = (menu, menuItems) => {
const SideMenuBar = ({
menuItems = [],
children,
state,
dispatch,
view,
className,
fileUpload
}) => (
......@@ -34,7 +33,7 @@ const SideMenuBar = ({
{
<span>
{map(setMenuItems(SideMenuItems, menuItems), item =>
item.menu({ state, dispatch, item, fileUpload })
item.menu({ view, item, fileUpload })
)}
</span>
}
......
......@@ -3,7 +3,7 @@ import debounce from "lodash/debounce";
import { DOMParser, DOMSerializer } from "prosemirror-model";
import Editor from "./Editor";
import WaxView from "./WaxView";
import defaultPlugins from "./config/defaultPlugins";
import placeholder from "./config/plugins/placeholder";
......@@ -72,6 +72,7 @@ class Wax extends Component {
render() {
const {
autoFocus,
children,
placeholder,
renderLayout,
fileUpload,
......@@ -83,28 +84,31 @@ class Wax extends Component {
theme,
debug
} = this.props;
const defaultRender = ({ editor, state, dispatch, fileUpload }) => (
<React.Fragment>{editor}</React.Fragment>
);
const WaxRender = renderLayout ? renderLayout : defaultRender;
const WaxRender = children.length ? children : defaultRender;
const WaxLayout = layout
? `wax-container wax-l-${layout}`
: "wax-container";
return (
<div className={`${WaxLayout} ${className}`}>
<Editor
<WaxView
autoFocus={autoFocus}
readonly={readonly}
options={this.WaxOptions}
placeholder={placeholder}
fileUpload={fileUpload}
renderLayout={WaxRender}
// renderLayout={WaxRender}
theme={theme}
onBlur={onBlur || (value => true)}
onChange={this.onChange || (value => true)}
debug={debug}
/>
>
{WaxRender}
</WaxView>
</div>
);
}
......
......@@ -8,38 +8,40 @@ import placeholderPlugin from "./config/plugins/placeholderPlugin";
import "prosemirror-view/style/prosemirror.css";
import "prosemirror-gapcursor/style/gapcursor.css";
class Editor extends Component {
class WaxView extends Component {
constructor(props) {
super(props);
this.state = {
state: EditorState.create(props.options)
};
const {readonly, onBlur } = this.props;
this.editorRef = React.createRef()
// Create view of Editor
this.view = new EditorView(null, {
editable: () => !readonly,
state: EditorState.create(props.options),
dispatchTransaction: this.dispatchTransaction,
fileUpload: this.uploadImage,
handleDOMEvents: {
blur: onBlur
? view => {
onBlur(view.state.doc.content);
}
: null
}
});
}
createEditorView = node => {
const { autoFocus, readonly, onBlur, debug } = this.props;
if (!this.view) {
this.view = new EditorView(node, {
editable: () => !readonly,
state: this.state.state,
dispatchTransaction: this.dispatchTransaction,
fileUpload: this.uploadImage,
handleDOMEvents: {
blur: onBlur
? view => {
onBlur(view.state.doc.content);
}
: null
}
});
componentDidMount() {
const { autoFocus, debug } = this.props;
this.editorRef.current.appendChild(this.view.dom)
if (debug) applyDevTools(this.view);
if (autoFocus) this.view.focus();
}
};
if (debug) applyDevTools(this.view);
if (autoFocus) this.view.focus();
}
uploadImage = file => {
const { state } = this.state;
const { state, dispatch } = this.view;
const { findPlaceholder } = this;
const { fileUpload } = this.props;
// A fresh object to act as the ID for this upload
......@@ -52,11 +54,12 @@ class Editor extends Component {
tr.setMeta(placeholderPlugin, {
add: { id, pos: tr.selection.from }
});
this.view.dispatch(tr);
dispatch(tr);
fileUpload(file).then(
url => {
const pos = this.findPlaceholder(this.view.state, id);
const pos = findPlaceholder(this.view.state, id);
// If the content around the placeholder has been deleted, drop
// the image
if (pos == null) {
......@@ -69,8 +72,8 @@ class Editor extends Component {
.replaceWith(
pos,
pos,
state.config.schema.nodes.image.create({
src: url.file
this.view.state.schema.nodes.image.create({
src: url
})
)
.setMeta(placeholderPlugin, { remove: { id } })
......@@ -78,13 +81,14 @@ class Editor extends Component {
},
() => {
// On failure, just clean up the placeholder
this.view.dispatch(tr.setMeta(placeholderPlugin, { remove: { id } }));
dispatch(tr.setMeta(placeholderPlugin, { remove: { id } }));
}
);
};
findPlaceholder = (state, id) => {
const decos = placeholderPlugin.getState(state);
debugger;
const found = decos.find(null, null, spec => spec.id === id);
return found.length ? found[0].from : null;
};
......@@ -92,7 +96,6 @@ class Editor extends Component {
dispatchTransaction = transaction => {
const state = this.view.state.apply(transaction);
this.view.updateState(state);
this.setState({ state });
this.props.onChange(state.doc.content);
};
......@@ -102,14 +105,13 @@ class Editor extends Component {
? `wax-surface-scroll wax-t-${theme}`
: "wax-surface-scroll";
const editor = <div ref={this.createEditorView} className={WaxTheme} />;
return this.props.renderLayout({
state: this.state.state,
dispatch: this.dispatchTransaction,
const editor = <div ref={this.editorRef} className={WaxTheme} />;
return this.props.children({
view: this.view,
fileUpload: this.uploadImage,
editor
});
}
}
export default Editor;
export default WaxView;
import { Plugin } from "prosemirror-state";
import { Plugin, PluginKey } from "prosemirror-state";
import { Decoration, DecorationSet } from "prosemirror-view";
const placeHolderText = new PluginKey("placeHolderText");
export default props => {
return new Plugin({
key: placeHolderText,
props: {
decorations: state => {
const decorations = [];
const decorate = (node, pos) => {
if (node.type.isBlock && node.childCount === 0) {
if (
node.type.isBlock &&
node.childCount === 0 &&
state.doc.content.childCount === 1
) {
decorations.push(
Decoration.node(pos, pos + node.nodeSize, {
class: "empty-node",
......
......@@ -12,7 +12,8 @@ class LinkToolTip {
constructor(view) {
this.tooltip = document.createElement("div");
this.tooltip.className = "tooltip";
view.dom.parentNode.appendChild(this.tooltip);
view.dom.appendChild(this.tooltip);
this.update(view, null);
}
......
......@@ -26,7 +26,24 @@ const EditoriaSchema = {
return brDOM;
}
},
image: {
inline: true,
attrs: {
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) { let {src, alt, title} = node.attrs; return ["img", {src, alt, title}] }
},
paragraph: {
content: "inline*",
group: "block",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment