diff --git a/README.md b/README.md
index d1a30ab4..7f4e6b25 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
draftail [![Build Status](https://travis-ci.org/springload/draftail.svg?branch=master)](https://travis-ci.org/springload/draftail) [![Dependency Status](https://david-dm.org/springload/draftail.svg?style=flat-square)](https://david-dm.org/springload/draftail) [![devDependency Status](https://david-dm.org/springload/draftail/dev-status.svg?style=flat-square)](https://david-dm.org/springload/draftail#info=devDependencies)
=========
-> A batteries-excluded rich text editor based on [Draft.js](https://facebook.github.io/draft-js/) :memo::cocktail:
+> A batteries-excluded rich text editor based on [Draft.js](https://facebook.github.io/draft-js/). :memo::cocktail:
This is a work in progress. It is intended to be integrated into [Wagtail](https://wagtail.io/).
@@ -43,5 +43,7 @@ npm run
```sh
git release x.y.z
npm run dist
+# Use irish-pub to check the package content. Install w/ npm install -g first.
+irish-pub
npm publish
```
diff --git a/lib/components/BlockControls.js b/lib/components/BlockControls.js
index 4a4ecf85..af9a4201 100644
--- a/lib/components/BlockControls.js
+++ b/lib/components/BlockControls.js
@@ -1,6 +1,6 @@
import React from 'react';
import StyleButton from './StyleButton';
-import * as DraftUtils from '../utils/DraftUtils';
+import DraftUtils from '../utils/DraftUtils';
const BlockControls = ({ editorState, styles, onToggle }) => (
diff --git a/lib/components/DraftailEditor.js b/lib/components/DraftailEditor.js
index a7f11bb0..55b188dc 100644
--- a/lib/components/DraftailEditor.js
+++ b/lib/components/DraftailEditor.js
@@ -12,7 +12,7 @@ import {
import { Map } from 'immutable';
-import * as DraftUtils from '../utils/DraftUtils';
+import DraftUtils from '../utils/DraftUtils';
// =============================================================================
// Config
@@ -108,10 +108,10 @@ class DraftailEditor extends Component {
}
handleFocus() {
- // if (this.refs.wrapper.contains(e.target)) {
+ // if (this.wrapperRef.contains(e.target)) {
// this.setState({readOnly: false}, () => {
// global.setTimeout(() => {
- // this.refs.editor.focus();
+ // this.editorRef.focus();
// }, 0)
// })
// } else {
@@ -121,9 +121,8 @@ class DraftailEditor extends Component {
saveRawState() {
const { editorState } = this.state;
- const input = this.refs.input;
- input.value = conversion.serialiseEditorState(editorState);
+ this.inputElt.value = conversion.serialiseEditorState(editorState);
}
// Sets a selection to encompass the containing entity.
@@ -165,14 +164,14 @@ class DraftailEditor extends Component {
const nextState = EditorState.acceptSelection(this.state.editorState, updatedSelection);
this.onChange(nextState);
- global.setTimeout(() => this.refs.editor.focus(), 0);
+ global.setTimeout(() => this.editorRef.focus(), 0);
}
}
updateState(state) {
this.onChange(state);
// not sure we need this.
- // setTimeout(() => this.refs.editor.focus(), 0);
+ // setTimeout(() => this.editorRef.focus(), 0);
return true;
}
@@ -347,7 +346,7 @@ class DraftailEditor extends Component {
global.setTimeout(() => {
this.setState({ readOnly: false }, () => {
global.setTimeout(() => {
- this.refs.editor.focus();
+ this.editorRef.focus();
}, 0);
});
}, 0);
@@ -499,7 +498,7 @@ class DraftailEditor extends Component {
return (
{ this.wrapperRef = ref; }}
className="json-text"
onBlur={this.saveRawState}
onClick={this.handleFocus}
@@ -509,7 +508,7 @@ class DraftailEditor extends Component {
{this.renderControls()}
{ this.editorRef = ref; }}
editorState={editorState}
onChange={this.onChange}
readOnly={readOnly}
@@ -520,7 +519,15 @@ class DraftailEditor extends Component {
blockRenderMap={blockRenderMap}
/>
-
+ {this.renderTooltip()}
+
+ {this.renderDialog()}
+
+ { this.inputElt = ref; }}
+ type="hidden"
+ name={name}
+ />
);
}
diff --git a/lib/index.js b/lib/index.js
index 6c8415ed..4b2164ff 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,3 +1,6 @@
import DraftailEditor from './components/DraftailEditor';
+import DraftUtils from './utils/DraftUtils';
export default DraftailEditor;
+
+export { DraftUtils };
diff --git a/lib/utils/DraftUtils.js b/lib/utils/DraftUtils.js
index 49f95e28..4e840cef 100644
--- a/lib/utils/DraftUtils.js
+++ b/lib/utils/DraftUtils.js
@@ -15,109 +15,110 @@ import DraftUtils from 'draftjs-utils';
/**
* Wrapper around draftjs-utils, with our custom functions.
- * import * as DraftUtils from '../utils/DraftUtils';
+ * import DraftUtils from '../utils/DraftUtils';
*/
-
-export const getSelectionEntity = DraftUtils.getSelectionEntity.bind(DraftUtils);
-
-export const getEntityRange = DraftUtils.getEntityRange.bind(DraftUtils);
-
-export const getEntityData = (entityKey) => {
- const entity = Entity.get(entityKey);
- return entity.getData();
-};
-
-/**
- * Returns the type of the block the current selection starts in.
- */
-export const getSelectedBlockType = (editorState) => {
- const selectionState = editorState.getSelection();
- const contentState = editorState.getCurrentContent();
- const startKey = selectionState.getStartKey();
- const block = contentState.getBlockForKey(startKey);
-
- return block.type;
-};
-
-/**
- * Creates a selection for the entirety of an entity that can be partially selected.
- */
-export const getSelectedEntitySelection = (editorState) => {
- const selectionState = editorState.getSelection();
- const contentState = editorState.getCurrentContent();
- const entityKey = getSelectionEntity(editorState);
- const entityRange = getEntityRange(editorState, entityKey);
- const anchorKey = selectionState.getAnchorKey();
- const block = contentState.getBlockForKey(anchorKey);
- const blockKey = block.getKey();
-
- return new SelectionState({
- anchorOffset: entityRange.start,
- anchorKey: blockKey,
- focusOffset: entityRange.end,
- focusKey: blockKey,
- isBackward: false,
- hasFocus: selectionState.getHasFocus(),
- });
-};
-
-// TODO Document.
-export const insertBlock = (editorState, entityKey, character, blockType) => {
- const contentState = editorState.getCurrentContent();
- const selectionState = editorState.getSelection();
-
- const afterRemoval = Modifier.removeRange(contentState, selectionState, 'backward');
-
- const targetSelection = afterRemoval.getSelectionAfter();
- const afterSplit = Modifier.splitBlock(afterRemoval, targetSelection);
- const insertionTarget = afterSplit.getSelectionAfter();
-
- const asAtomicBlock = Modifier.setBlockType(afterSplit, insertionTarget, blockType);
-
- const charData = CharacterMetadata.create({ entity: entityKey });
-
- const fragmentArray = [
- new ContentBlock({
- key: genKey(),
- type: blockType,
- text: character,
- characterList: List(Repeat(charData, character.length)),
- }),
- new ContentBlock({
- key: genKey(),
- type: 'unstyled',
- text: '',
- characterList: List(),
- }),
- ];
-
- const fragment = BlockMapBuilder.createFromArray(fragmentArray);
-
- const withBlock = Modifier.replaceWithFragment(asAtomicBlock, insertionTarget, fragment);
-
- const newContent = withBlock.merge({
- selectionBefore: selectionState,
- selectionAfter: withBlock.getSelectionAfter().set('hasFocus', true),
- });
-
- return EditorState.push(editorState, newContent, 'insert-fragment');
-};
-
-// TODO Document.
-export const createEntity = (editorState, entityType, entityData, entityText, entityMutability = 'IMMUTABLE') => {
- const entityKey = Entity.create(entityType, entityMutability, entityData);
-
- const contentState = editorState.getCurrentContent();
- const selection = editorState.getSelection();
-
- let nextContentState;
-
- if (selection.isCollapsed()) {
- nextContentState = Modifier.insertText(contentState, editorState.getSelection(), entityText, null, entityKey);
- } else {
- nextContentState = Modifier.replaceText(contentState, editorState.getSelection(), entityText, null, entityKey);
- }
-
- const nextState = EditorState.push(editorState, nextContentState, 'insert');
- return nextState;
+export default {
+ getSelectionEntity: DraftUtils.getSelectionEntity.bind(DraftUtils),
+
+ getEntityRange: DraftUtils.getEntityRange.bind(DraftUtils),
+
+ getEntityData: (entityKey) => {
+ const entity = Entity.get(entityKey);
+ return entity.getData();
+ },
+
+ /**
+ * Returns the type of the block the current selection starts in.
+ */
+ getSelectedBlockType: (editorState) => {
+ const selectionState = editorState.getSelection();
+ const contentState = editorState.getCurrentContent();
+ const startKey = selectionState.getStartKey();
+ const block = contentState.getBlockForKey(startKey);
+
+ return block.type;
+ },
+
+ /**
+ * Creates a selection for the entirety of an entity that can be partially selected.
+ */
+ getSelectedEntitySelection: (editorState) => {
+ const selectionState = editorState.getSelection();
+ const contentState = editorState.getCurrentContent();
+ const entityKey = getSelectionEntity(editorState);
+ const entityRange = getEntityRange(editorState, entityKey);
+ const anchorKey = selectionState.getAnchorKey();
+ const block = contentState.getBlockForKey(anchorKey);
+ const blockKey = block.getKey();
+
+ return new SelectionState({
+ anchorOffset: entityRange.start,
+ anchorKey: blockKey,
+ focusOffset: entityRange.end,
+ focusKey: blockKey,
+ isBackward: false,
+ hasFocus: selectionState.getHasFocus(),
+ });
+ },
+
+ // TODO Document.
+ insertBlock: (editorState, entityKey, character, blockType) => {
+ const contentState = editorState.getCurrentContent();
+ const selectionState = editorState.getSelection();
+
+ const afterRemoval = Modifier.removeRange(contentState, selectionState, 'backward');
+
+ const targetSelection = afterRemoval.getSelectionAfter();
+ const afterSplit = Modifier.splitBlock(afterRemoval, targetSelection);
+ const insertionTarget = afterSplit.getSelectionAfter();
+
+ const asAtomicBlock = Modifier.setBlockType(afterSplit, insertionTarget, blockType);
+
+ const charData = CharacterMetadata.create({ entity: entityKey });
+
+ const fragmentArray = [
+ new ContentBlock({
+ key: genKey(),
+ type: blockType,
+ text: character,
+ characterList: List(Repeat(charData, character.length)),
+ }),
+ new ContentBlock({
+ key: genKey(),
+ type: 'unstyled',
+ text: '',
+ characterList: List(),
+ }),
+ ];
+
+ const fragment = BlockMapBuilder.createFromArray(fragmentArray);
+
+ const withBlock = Modifier.replaceWithFragment(asAtomicBlock, insertionTarget, fragment);
+
+ const newContent = withBlock.merge({
+ selectionBefore: selectionState,
+ selectionAfter: withBlock.getSelectionAfter().set('hasFocus', true),
+ });
+
+ return EditorState.push(editorState, newContent, 'insert-fragment');
+ },
+
+ // TODO Document.
+ createEntity: (editorState, entityType, entityData, entityText, entityMutability = 'IMMUTABLE') => {
+ const entityKey = Entity.create(entityType, entityMutability, entityData);
+
+ const contentState = editorState.getCurrentContent();
+ const selection = editorState.getSelection();
+
+ let nextContentState;
+
+ if (selection.isCollapsed()) {
+ nextContentState = Modifier.insertText(contentState, editorState.getSelection(), entityText, null, entityKey);
+ } else {
+ nextContentState = Modifier.replaceText(contentState, editorState.getSelection(), entityText, null, entityKey);
+ }
+
+ const nextState = EditorState.push(editorState, nextContentState, 'insert');
+ return nextState;
+ },
};
diff --git a/lib/utils/DraftUtils.test.js b/lib/utils/DraftUtils.test.js
index cf6a743d..96e1959d 100644
--- a/lib/utils/DraftUtils.test.js
+++ b/lib/utils/DraftUtils.test.js
@@ -6,7 +6,7 @@ import {
ContentState,
} from 'draft-js';
-import * as DraftUtils from '../utils/DraftUtils';
+import DraftUtils from '../utils/DraftUtils';
describe('DraftUtils', () => {
describe('#getEntityData', () => {
diff --git a/package.json b/package.json
index 99492190..1495e1e1 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "draftail",
"version": "0.1.0",
- "description": "",
+ "description": "A batteries-excluded rich text editor based on Draft.js",
"main": "dist/index.js",
"keywords": [
"draftjs",
diff --git a/server/index.js b/server/index.js
index d6d28cad..f6ec00dc 100644
--- a/server/index.js
+++ b/server/index.js
@@ -12,7 +12,7 @@ const compiler = webpack(config);
const PORT = process.env.PORT || 3000;
-app.use('/', express.static(path.join(__dirname, '..', 'docs')));
+app.use('/', express.static(path.join(__dirname, '..', 'examples')));
app.use(webpackDev(compiler, {
noInfo: true,
@@ -21,8 +21,8 @@ app.use(webpackDev(compiler, {
app.use(webpackHot(compiler));
-app.get('*', (req, res) => {
- res.sendFile(path.join(__dirname, '..', 'docs/index.html'));
+app.get('/', (req, res) => {
+ res.sendFile(path.join(__dirname, '..', 'examples/index.html'));
});
app.listen(PORT, 'localhost', () => {
diff --git a/webpack.config.dev.js b/webpack.config.dev.js
index 0f3bd27b..bef5629b 100644
--- a/webpack.config.dev.js
+++ b/webpack.config.dev.js
@@ -7,19 +7,21 @@ const ProgressBarPlugin = require('progress-bar-webpack-plugin');
module.exports = {
// See http://webpack.github.io/docs/configuration.html#devtool
devtool: 'inline-source-map',
- entry: [
- 'webpack-hot-middleware/client',
- './examples/index',
- ],
+ entry: {
+ hmr: 'webpack-hot-middleware/client',
+ basic: './examples/basic',
+ entities: './examples/entities',
+ },
output: {
path: path.join(__dirname, 'build'),
- filename: 'examples.bundle.js',
+ filename: '[name].bundle.js',
publicPath: '/',
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new ProgressBarPlugin(),
+ new webpack.optimize.CommonsChunkPlugin('common', 'common.bundle.js', Infinity),
],
module: {
loaders: [
diff --git a/webpack.config.prod.js b/webpack.config.prod.js
index dcec2320..93ee6187 100644
--- a/webpack.config.prod.js
+++ b/webpack.config.prod.js
@@ -5,9 +5,9 @@ const webpack = require('webpack');
const config = require('./webpack.config.dev');
// Lose the webpack middleware
-config.entry.shift();
+delete config.entry.hmr;
config.watch = false;
-config.devtool = '';
+config.devtool = false;
config.output.path = path.join(__dirname, 'docs');
config.plugins = [