Skip to content

Commit cf96454

Browse files
committed
Refine package interface
1 parent 6ed5f98 commit cf96454

File tree

10 files changed

+144
-129
lines changed

10 files changed

+144
-129
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
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)
22
=========
33

4-
> A batteries-excluded rich text editor based on [Draft.js](https://facebook.github.io/draft-js/) :memo::cocktail:
4+
> A batteries-excluded rich text editor based on [Draft.js](https://facebook.github.io/draft-js/). :memo::cocktail:
55
66
This is a work in progress. It is intended to be integrated into [Wagtail](https://wagtail.io/).
77

@@ -43,5 +43,7 @@ npm run
4343
```sh
4444
git release x.y.z
4545
npm run dist
46+
# Use irish-pub to check the package content. Install w/ npm install -g first.
47+
irish-pub
4648
npm publish
4749
```

lib/components/BlockControls.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import StyleButton from './StyleButton';
3-
import * as DraftUtils from '../utils/DraftUtils';
3+
import DraftUtils from '../utils/DraftUtils';
44

55
const BlockControls = ({ editorState, styles, onToggle }) => (
66
<div className="RichEditor-controls">

lib/components/DraftailEditor.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212

1313
import { Map } from 'immutable';
1414

15-
import * as DraftUtils from '../utils/DraftUtils';
15+
import DraftUtils from '../utils/DraftUtils';
1616

1717
// =============================================================================
1818
// Config
@@ -108,10 +108,10 @@ class DraftailEditor extends Component {
108108
}
109109

110110
handleFocus() {
111-
// if (this.refs.wrapper.contains(e.target)) {
111+
// if (this.wrapperRef.contains(e.target)) {
112112
// this.setState({readOnly: false}, () => {
113113
// global.setTimeout(() => {
114-
// this.refs.editor.focus();
114+
// this.editorRef.focus();
115115
// }, 0)
116116
// })
117117
// } else {
@@ -121,9 +121,8 @@ class DraftailEditor extends Component {
121121

122122
saveRawState() {
123123
const { editorState } = this.state;
124-
const input = this.refs.input;
125124

126-
input.value = conversion.serialiseEditorState(editorState);
125+
this.inputElt.value = conversion.serialiseEditorState(editorState);
127126
}
128127

129128
// Sets a selection to encompass the containing entity.
@@ -165,14 +164,14 @@ class DraftailEditor extends Component {
165164
const nextState = EditorState.acceptSelection(this.state.editorState, updatedSelection);
166165
this.onChange(nextState);
167166

168-
global.setTimeout(() => this.refs.editor.focus(), 0);
167+
global.setTimeout(() => this.editorRef.focus(), 0);
169168
}
170169
}
171170

172171
updateState(state) {
173172
this.onChange(state);
174173
// not sure we need this.
175-
// setTimeout(() => this.refs.editor.focus(), 0);
174+
// setTimeout(() => this.editorRef.focus(), 0);
176175
return true;
177176
}
178177

@@ -347,7 +346,7 @@ class DraftailEditor extends Component {
347346
global.setTimeout(() => {
348347
this.setState({ readOnly: false }, () => {
349348
global.setTimeout(() => {
350-
this.refs.editor.focus();
349+
this.editorRef.focus();
351350
}, 0);
352351
});
353352
}, 0);
@@ -499,7 +498,7 @@ class DraftailEditor extends Component {
499498

500499
return (
501500
<div
502-
ref="wrapper"
501+
ref={(ref) => { this.wrapperRef = ref; }}
503502
className="json-text"
504503
onBlur={this.saveRawState}
505504
onClick={this.handleFocus}
@@ -509,7 +508,7 @@ class DraftailEditor extends Component {
509508
{this.renderControls()}
510509

511510
<Editor
512-
ref="editor"
511+
ref={(ref) => { this.editorRef = ref; }}
513512
editorState={editorState}
514513
onChange={this.onChange}
515514
readOnly={readOnly}
@@ -520,7 +519,15 @@ class DraftailEditor extends Component {
520519
blockRenderMap={blockRenderMap}
521520
/>
522521

523-
<input ref="input" type="hidden" name={name} />
522+
{this.renderTooltip()}
523+
524+
{this.renderDialog()}
525+
526+
<input
527+
ref={(ref) => { this.inputElt = ref; }}
528+
type="hidden"
529+
name={name}
530+
/>
524531
</div>
525532
);
526533
}

lib/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
import DraftailEditor from './components/DraftailEditor';
2+
import DraftUtils from './utils/DraftUtils';
23

34
export default DraftailEditor;
5+
6+
export { DraftUtils };

lib/utils/DraftUtils.js

Lines changed: 105 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -15,109 +15,110 @@ import DraftUtils from 'draftjs-utils';
1515

1616
/**
1717
* Wrapper around draftjs-utils, with our custom functions.
18-
* import * as DraftUtils from '../utils/DraftUtils';
18+
* import DraftUtils from '../utils/DraftUtils';
1919
*/
20-
21-
export const getSelectionEntity = DraftUtils.getSelectionEntity.bind(DraftUtils);
22-
23-
export const getEntityRange = DraftUtils.getEntityRange.bind(DraftUtils);
24-
25-
export const getEntityData = (entityKey) => {
26-
const entity = Entity.get(entityKey);
27-
return entity.getData();
28-
};
29-
30-
/**
31-
* Returns the type of the block the current selection starts in.
32-
*/
33-
export const getSelectedBlockType = (editorState) => {
34-
const selectionState = editorState.getSelection();
35-
const contentState = editorState.getCurrentContent();
36-
const startKey = selectionState.getStartKey();
37-
const block = contentState.getBlockForKey(startKey);
38-
39-
return block.type;
40-
};
41-
42-
/**
43-
* Creates a selection for the entirety of an entity that can be partially selected.
44-
*/
45-
export const getSelectedEntitySelection = (editorState) => {
46-
const selectionState = editorState.getSelection();
47-
const contentState = editorState.getCurrentContent();
48-
const entityKey = getSelectionEntity(editorState);
49-
const entityRange = getEntityRange(editorState, entityKey);
50-
const anchorKey = selectionState.getAnchorKey();
51-
const block = contentState.getBlockForKey(anchorKey);
52-
const blockKey = block.getKey();
53-
54-
return new SelectionState({
55-
anchorOffset: entityRange.start,
56-
anchorKey: blockKey,
57-
focusOffset: entityRange.end,
58-
focusKey: blockKey,
59-
isBackward: false,
60-
hasFocus: selectionState.getHasFocus(),
61-
});
62-
};
63-
64-
// TODO Document.
65-
export const insertBlock = (editorState, entityKey, character, blockType) => {
66-
const contentState = editorState.getCurrentContent();
67-
const selectionState = editorState.getSelection();
68-
69-
const afterRemoval = Modifier.removeRange(contentState, selectionState, 'backward');
70-
71-
const targetSelection = afterRemoval.getSelectionAfter();
72-
const afterSplit = Modifier.splitBlock(afterRemoval, targetSelection);
73-
const insertionTarget = afterSplit.getSelectionAfter();
74-
75-
const asAtomicBlock = Modifier.setBlockType(afterSplit, insertionTarget, blockType);
76-
77-
const charData = CharacterMetadata.create({ entity: entityKey });
78-
79-
const fragmentArray = [
80-
new ContentBlock({
81-
key: genKey(),
82-
type: blockType,
83-
text: character,
84-
characterList: List(Repeat(charData, character.length)),
85-
}),
86-
new ContentBlock({
87-
key: genKey(),
88-
type: 'unstyled',
89-
text: '',
90-
characterList: List(),
91-
}),
92-
];
93-
94-
const fragment = BlockMapBuilder.createFromArray(fragmentArray);
95-
96-
const withBlock = Modifier.replaceWithFragment(asAtomicBlock, insertionTarget, fragment);
97-
98-
const newContent = withBlock.merge({
99-
selectionBefore: selectionState,
100-
selectionAfter: withBlock.getSelectionAfter().set('hasFocus', true),
101-
});
102-
103-
return EditorState.push(editorState, newContent, 'insert-fragment');
104-
};
105-
106-
// TODO Document.
107-
export const createEntity = (editorState, entityType, entityData, entityText, entityMutability = 'IMMUTABLE') => {
108-
const entityKey = Entity.create(entityType, entityMutability, entityData);
109-
110-
const contentState = editorState.getCurrentContent();
111-
const selection = editorState.getSelection();
112-
113-
let nextContentState;
114-
115-
if (selection.isCollapsed()) {
116-
nextContentState = Modifier.insertText(contentState, editorState.getSelection(), entityText, null, entityKey);
117-
} else {
118-
nextContentState = Modifier.replaceText(contentState, editorState.getSelection(), entityText, null, entityKey);
119-
}
120-
121-
const nextState = EditorState.push(editorState, nextContentState, 'insert');
122-
return nextState;
20+
export default {
21+
getSelectionEntity: DraftUtils.getSelectionEntity.bind(DraftUtils),
22+
23+
getEntityRange: DraftUtils.getEntityRange.bind(DraftUtils),
24+
25+
getEntityData: (entityKey) => {
26+
const entity = Entity.get(entityKey);
27+
return entity.getData();
28+
},
29+
30+
/**
31+
* Returns the type of the block the current selection starts in.
32+
*/
33+
getSelectedBlockType: (editorState) => {
34+
const selectionState = editorState.getSelection();
35+
const contentState = editorState.getCurrentContent();
36+
const startKey = selectionState.getStartKey();
37+
const block = contentState.getBlockForKey(startKey);
38+
39+
return block.type;
40+
},
41+
42+
/**
43+
* Creates a selection for the entirety of an entity that can be partially selected.
44+
*/
45+
getSelectedEntitySelection: (editorState) => {
46+
const selectionState = editorState.getSelection();
47+
const contentState = editorState.getCurrentContent();
48+
const entityKey = getSelectionEntity(editorState);
49+
const entityRange = getEntityRange(editorState, entityKey);
50+
const anchorKey = selectionState.getAnchorKey();
51+
const block = contentState.getBlockForKey(anchorKey);
52+
const blockKey = block.getKey();
53+
54+
return new SelectionState({
55+
anchorOffset: entityRange.start,
56+
anchorKey: blockKey,
57+
focusOffset: entityRange.end,
58+
focusKey: blockKey,
59+
isBackward: false,
60+
hasFocus: selectionState.getHasFocus(),
61+
});
62+
},
63+
64+
// TODO Document.
65+
insertBlock: (editorState, entityKey, character, blockType) => {
66+
const contentState = editorState.getCurrentContent();
67+
const selectionState = editorState.getSelection();
68+
69+
const afterRemoval = Modifier.removeRange(contentState, selectionState, 'backward');
70+
71+
const targetSelection = afterRemoval.getSelectionAfter();
72+
const afterSplit = Modifier.splitBlock(afterRemoval, targetSelection);
73+
const insertionTarget = afterSplit.getSelectionAfter();
74+
75+
const asAtomicBlock = Modifier.setBlockType(afterSplit, insertionTarget, blockType);
76+
77+
const charData = CharacterMetadata.create({ entity: entityKey });
78+
79+
const fragmentArray = [
80+
new ContentBlock({
81+
key: genKey(),
82+
type: blockType,
83+
text: character,
84+
characterList: List(Repeat(charData, character.length)),
85+
}),
86+
new ContentBlock({
87+
key: genKey(),
88+
type: 'unstyled',
89+
text: '',
90+
characterList: List(),
91+
}),
92+
];
93+
94+
const fragment = BlockMapBuilder.createFromArray(fragmentArray);
95+
96+
const withBlock = Modifier.replaceWithFragment(asAtomicBlock, insertionTarget, fragment);
97+
98+
const newContent = withBlock.merge({
99+
selectionBefore: selectionState,
100+
selectionAfter: withBlock.getSelectionAfter().set('hasFocus', true),
101+
});
102+
103+
return EditorState.push(editorState, newContent, 'insert-fragment');
104+
},
105+
106+
// TODO Document.
107+
createEntity: (editorState, entityType, entityData, entityText, entityMutability = 'IMMUTABLE') => {
108+
const entityKey = Entity.create(entityType, entityMutability, entityData);
109+
110+
const contentState = editorState.getCurrentContent();
111+
const selection = editorState.getSelection();
112+
113+
let nextContentState;
114+
115+
if (selection.isCollapsed()) {
116+
nextContentState = Modifier.insertText(contentState, editorState.getSelection(), entityText, null, entityKey);
117+
} else {
118+
nextContentState = Modifier.replaceText(contentState, editorState.getSelection(), entityText, null, entityKey);
119+
}
120+
121+
const nextState = EditorState.push(editorState, nextContentState, 'insert');
122+
return nextState;
123+
},
123124
};

lib/utils/DraftUtils.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ContentState,
77
} from 'draft-js';
88

9-
import * as DraftUtils from '../utils/DraftUtils';
9+
import DraftUtils from '../utils/DraftUtils';
1010

1111
describe('DraftUtils', () => {
1212
describe('#getEntityData', () => {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "draftail",
33
"version": "0.1.0",
4-
"description": "",
4+
"description": "A batteries-excluded rich text editor based on Draft.js",
55
"main": "dist/index.js",
66
"keywords": [
77
"draftjs",

server/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const compiler = webpack(config);
1212

1313
const PORT = process.env.PORT || 3000;
1414

15-
app.use('/', express.static(path.join(__dirname, '..', 'docs')));
15+
app.use('/', express.static(path.join(__dirname, '..', 'examples')));
1616

1717
app.use(webpackDev(compiler, {
1818
noInfo: true,
@@ -21,8 +21,8 @@ app.use(webpackDev(compiler, {
2121

2222
app.use(webpackHot(compiler));
2323

24-
app.get('*', (req, res) => {
25-
res.sendFile(path.join(__dirname, '..', 'docs/index.html'));
24+
app.get('/', (req, res) => {
25+
res.sendFile(path.join(__dirname, '..', 'examples/index.html'));
2626
});
2727

2828
app.listen(PORT, 'localhost', () => {

0 commit comments

Comments
 (0)