Skip to content

Commit

Permalink
Refine package interface
Browse files Browse the repository at this point in the history
  • Loading branch information
thibaudcolas committed Nov 13, 2016
1 parent 6ed5f98 commit cf96454
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 129 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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/).

Expand Down Expand Up @@ -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
```
2 changes: 1 addition & 1 deletion lib/components/BlockControls.js
Original file line number Diff line number Diff line change
@@ -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 }) => (
<div className="RichEditor-controls">
Expand Down
29 changes: 18 additions & 11 deletions lib/components/DraftailEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {

import { Map } from 'immutable';

import * as DraftUtils from '../utils/DraftUtils';
import DraftUtils from '../utils/DraftUtils';

// =============================================================================
// Config
Expand Down Expand Up @@ -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 {
Expand All @@ -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.
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -499,7 +498,7 @@ class DraftailEditor extends Component {

return (
<div
ref="wrapper"
ref={(ref) => { this.wrapperRef = ref; }}
className="json-text"
onBlur={this.saveRawState}
onClick={this.handleFocus}
Expand All @@ -509,7 +508,7 @@ class DraftailEditor extends Component {
{this.renderControls()}

<Editor
ref="editor"
ref={(ref) => { this.editorRef = ref; }}
editorState={editorState}
onChange={this.onChange}
readOnly={readOnly}
Expand All @@ -520,7 +519,15 @@ class DraftailEditor extends Component {
blockRenderMap={blockRenderMap}
/>

<input ref="input" type="hidden" name={name} />
{this.renderTooltip()}

{this.renderDialog()}

<input
ref={(ref) => { this.inputElt = ref; }}
type="hidden"
name={name}
/>
</div>
);
}
Expand Down
3 changes: 3 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import DraftailEditor from './components/DraftailEditor';
import DraftUtils from './utils/DraftUtils';

export default DraftailEditor;

export { DraftUtils };
209 changes: 105 additions & 104 deletions lib/utils/DraftUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},
};
2 changes: 1 addition & 1 deletion lib/utils/DraftUtils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ContentState,
} from 'draft-js';

import * as DraftUtils from '../utils/DraftUtils';
import DraftUtils from '../utils/DraftUtils';

describe('DraftUtils', () => {
describe('#getEntityData', () => {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
6 changes: 3 additions & 3 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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', () => {
Expand Down
Loading

0 comments on commit cf96454

Please sign in to comment.