Added drag'n'drop image adding to VisualEditor.
Removed StylesMenu and BlockTypesMenu positioning code since it didn't work with adding images using DnD.
This commit is contained in:
parent
e454144d31
commit
e644104542
@ -1,9 +1,10 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { Editor, Raw } from 'slate';
|
import { Editor, Raw } from 'slate';
|
||||||
import position from 'selection-position';
|
import PluginDropImages from 'slate-drop-or-paste-images';
|
||||||
import MarkupIt, { SlateUtils } from 'markup-it';
|
import MarkupIt, { SlateUtils } from 'markup-it';
|
||||||
import { emptyParagraphBlock } from '../constants';
|
import MediaProxy from '../../../../valueObjects/MediaProxy';
|
||||||
|
import { emptyParagraphBlock, mediaproxyBlock } from '../constants';
|
||||||
import { DEFAULT_NODE, SCHEMA } from './schema';
|
import { DEFAULT_NODE, SCHEMA } from './schema';
|
||||||
import { getNodes, getSyntaxes, getPlugins } from '../../richText';
|
import { getNodes, getSyntaxes, getPlugins } from '../../richText';
|
||||||
import StylesMenu from './StylesMenu';
|
import StylesMenu from './StylesMenu';
|
||||||
@ -23,25 +24,10 @@ class VisualEditor extends React.Component {
|
|||||||
SCHEMA.nodes = _.merge(SCHEMA.nodes, getNodes());
|
SCHEMA.nodes = _.merge(SCHEMA.nodes, getNodes());
|
||||||
|
|
||||||
this.blockEdit = false;
|
this.blockEdit = false;
|
||||||
this.menuPositions = {
|
|
||||||
stylesMenu: {
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
width: 0,
|
|
||||||
height: 0
|
|
||||||
},
|
|
||||||
blockTypesMenu: {
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
width: 0,
|
|
||||||
height: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let rawJson;
|
let rawJson;
|
||||||
if (props.value !== undefined) {
|
if (props.value !== undefined) {
|
||||||
const content = this.markdown.toContent(props.value);
|
const content = this.markdown.toContent(props.value);
|
||||||
console.log('md: %o', content);
|
|
||||||
rawJson = SlateUtils.encode(content, null, ['mediaproxy'].concat(getPlugins().map(plugin => plugin.id)));
|
rawJson = SlateUtils.encode(content, null, ['mediaproxy'].concat(getPlugins().map(plugin => plugin.id)));
|
||||||
} else {
|
} else {
|
||||||
rawJson = emptyParagraphBlock;
|
rawJson = emptyParagraphBlock;
|
||||||
@ -50,6 +36,17 @@ class VisualEditor extends React.Component {
|
|||||||
state: Raw.deserialize(rawJson, { terse: true })
|
state: Raw.deserialize(rawJson, { terse: true })
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.plugins = [
|
||||||
|
PluginDropImages({
|
||||||
|
applyTransform: (transform, file) => {
|
||||||
|
const mediaProxy = new MediaProxy(file.name, file);
|
||||||
|
props.onAddMedia(mediaProxy);
|
||||||
|
return transform
|
||||||
|
.insertBlock(mediaproxyBlock(mediaProxy));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
this.handleChange = this.handleChange.bind(this);
|
||||||
this.handleDocumentChange = this.handleDocumentChange.bind(this);
|
this.handleDocumentChange = this.handleDocumentChange.bind(this);
|
||||||
this.handleMarkStyleClick = this.handleMarkStyleClick.bind(this);
|
this.handleMarkStyleClick = this.handleMarkStyleClick.bind(this);
|
||||||
@ -60,8 +57,6 @@ class VisualEditor extends React.Component {
|
|||||||
this.handleImageClick = this.handleImageClick.bind(this);
|
this.handleImageClick = this.handleImageClick.bind(this);
|
||||||
this.focusAndAddParagraph = this.focusAndAddParagraph.bind(this);
|
this.focusAndAddParagraph = this.focusAndAddParagraph.bind(this);
|
||||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
this.calculateHoverMenuPosition = _.throttle(this.calculateHoverMenuPosition.bind(this), 30);
|
|
||||||
this.calculateBlockMenuPosition = _.throttle(this.calculateBlockMenuPosition.bind(this), 100);
|
|
||||||
this.renderBlockTypesMenu = this.renderBlockTypesMenu.bind(this);
|
this.renderBlockTypesMenu = this.renderBlockTypesMenu.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,8 +74,7 @@ class VisualEditor extends React.Component {
|
|||||||
if (this.blockEdit) {
|
if (this.blockEdit) {
|
||||||
this.blockEdit = false;
|
this.blockEdit = false;
|
||||||
} else {
|
} else {
|
||||||
this.calculateHoverMenuPosition();
|
this.setState({ state });
|
||||||
this.setState({ state }, this.calculateBlockMenuPosition);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,32 +84,6 @@ class VisualEditor extends React.Component {
|
|||||||
this.props.onChange(this.markdown.toText(content));
|
this.props.onChange(this.markdown.toText(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateHoverMenuPosition() {
|
|
||||||
const rect = position();
|
|
||||||
this.menuPositions.stylesMenu = {
|
|
||||||
top: rect.top + window.scrollY,
|
|
||||||
left: rect.left + window.scrollX,
|
|
||||||
width: rect.width,
|
|
||||||
height: rect.height
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateBlockMenuPosition() {
|
|
||||||
// Don't bother calculating position if block is not empty
|
|
||||||
if (this.state.state.blocks.get(0).isEmpty) {
|
|
||||||
const blockElement = document.querySelectorAll(`[data-key='${this.state.state.selection.focusKey}']`);
|
|
||||||
if (blockElement.length > 0) {
|
|
||||||
const rect = blockElement[0].getBoundingClientRect();
|
|
||||||
this.menuPositions.blockTypesMenu = {
|
|
||||||
top: rect.top + window.scrollY,
|
|
||||||
left: rect.left + window.scrollX
|
|
||||||
};
|
|
||||||
// Force re-render so the menu is positioned on these new coordinates
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle marks / blocks when button is clicked
|
* Toggle marks / blocks when button is clicked
|
||||||
*/
|
*/
|
||||||
@ -197,7 +165,7 @@ class VisualEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
const href = window.prompt('Enter the URL of the link:', 'http://www.');
|
const href = window.prompt('Enter the URL of the link:', 'http://www.'); // eslint-disable-line
|
||||||
state = state
|
state = state
|
||||||
.transform()
|
.transform()
|
||||||
.wrapInline({
|
.wrapInline({
|
||||||
@ -249,14 +217,7 @@ class VisualEditor extends React.Component {
|
|||||||
|
|
||||||
state = state
|
state = state
|
||||||
.transform()
|
.transform()
|
||||||
.insertInline({
|
.insertBlock(mediaproxyBlock(mediaProxy))
|
||||||
type: 'mediaproxy',
|
|
||||||
isVoid: true,
|
|
||||||
data: { src: mediaProxy.public_path }
|
|
||||||
})
|
|
||||||
.collapseToEnd()
|
|
||||||
.insertBlock(DEFAULT_NODE)
|
|
||||||
.focus()
|
|
||||||
.apply();
|
.apply();
|
||||||
|
|
||||||
this.setState({ state });
|
this.setState({ state });
|
||||||
@ -299,7 +260,6 @@ class VisualEditor extends React.Component {
|
|||||||
<BlockTypesMenu
|
<BlockTypesMenu
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
plugins={getPlugins()}
|
plugins={getPlugins()}
|
||||||
position={this.menuPositions.blockTypesMenu}
|
|
||||||
onClickBlock={this.handleBlockTypeClick}
|
onClickBlock={this.handleBlockTypeClick}
|
||||||
onClickPlugin={this.handlePluginClick}
|
onClickPlugin={this.handlePluginClick}
|
||||||
onClickImage={this.handleImageClick}
|
onClickImage={this.handleImageClick}
|
||||||
@ -314,7 +274,6 @@ class VisualEditor extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<StylesMenu
|
<StylesMenu
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
position={this.menuPositions.stylesMenu}
|
|
||||||
marks={this.state.state.marks}
|
marks={this.state.state.marks}
|
||||||
blocks={this.state.state.blocks}
|
blocks={this.state.state.blocks}
|
||||||
inlines={this.state.state.inlines}
|
inlines={this.state.state.inlines}
|
||||||
@ -334,6 +293,7 @@ class VisualEditor extends React.Component {
|
|||||||
placeholder={'Enter some rich text...'}
|
placeholder={'Enter some rich text...'}
|
||||||
state={this.state.state}
|
state={this.state.state}
|
||||||
schema={SCHEMA}
|
schema={SCHEMA}
|
||||||
|
plugins={this.plugins}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
onDocumentChange={this.handleDocumentChange}
|
onDocumentChange={this.handleDocumentChange}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export const emptyParagraphBlock = {
|
export const emptyParagraphBlock = {
|
||||||
nodes: [
|
nodes: [
|
||||||
{ kind: 'block',
|
{
|
||||||
|
kind: 'block',
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
nodes: [{
|
nodes: [{
|
||||||
kind: 'text',
|
kind: 'text',
|
||||||
@ -11,3 +12,17 @@ export const emptyParagraphBlock = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const mediaproxyBlock = mediaproxy => ({
|
||||||
|
kind: 'block',
|
||||||
|
type: 'paragraph',
|
||||||
|
nodes: [{
|
||||||
|
kind: 'inline',
|
||||||
|
type: 'mediaproxy',
|
||||||
|
isVoid: true,
|
||||||
|
data: {
|
||||||
|
alt: mediaproxy.name,
|
||||||
|
src: mediaproxy.public_path
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user