Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate rich text editor to Slate backed by Unified #254

Merged
merged 79 commits into from
Aug 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
f3b7dc9
Update Jest to 0.19
KyleAMathews Mar 1, 2017
24c0a1b
Replace markup-it with Remark for rendering markdown in the editor pr…
KyleAMathews Mar 1, 2017
0eb109c
Convert markdown-prosemirror parser/compiler to Remark
KyleAMathews Mar 2, 2017
8763666
Update parser to support remaining node types + add inline styled tex…
KyleAMathews Mar 18, 2017
f93aa34
fix rebase incongruencies
May 22, 2017
e401f7e
remove unrelated code style improvements
May 22, 2017
514fbb3
render plugins on visual editor load
erquhart May 23, 2017
adcb215
replace remark with unified for docs and extensibility
erquhart May 24, 2017
5048c7c
convert editor component registry to Map
erquhart May 24, 2017
8bb1845
implement initial unified/remark preview update
erquhart May 25, 2017
361c3d5
improve prosemirror parser, fix new doc creation
erquhart Jun 8, 2017
b5e0be4
split off markdownToProseMirror plugin
erquhart Jun 9, 2017
b223232
handle raw editor html pastes with unified
erquhart Jun 9, 2017
bd76730
fix visual editor tests, parse/serialize consistency
erquhart Jun 10, 2017
b293b23
fix link creation in visual editor
erquhart Jun 13, 2017
e7ac3a7
switch remark options to use gfm, fences
erquhart Jun 13, 2017
49b3a62
attempt prosemirror update, troubleshooting
erquhart Jun 15, 2017
9c869be
migrate visual editor from prosemirror to slate
erquhart Jun 19, 2017
e01c077
fix empty initial state for rte
erquhart Jun 20, 2017
e682189
only render editor page controls/previews on change
erquhart Jun 21, 2017
22a8da1
fix rte link serialization
erquhart Jun 21, 2017
bc72133
set rte focus after toolbar click
erquhart Jun 21, 2017
1c0bb6a
implement widget data serialization for rte perf
erquhart Jun 21, 2017
ffbd8d2
expose widgetValueSerializer registry
erquhart Jun 22, 2017
84ed450
add visual editor serializer source doc
erquhart Jun 22, 2017
09e631d
allow nested widget previews to update
erquhart Jun 23, 2017
e0ca24c
add unified config module
erquhart Jun 23, 2017
faec38a
fix raw editor paste parsing
erquhart Jun 23, 2017
54e77bd
fix raw editor formatting controls
erquhart Jun 23, 2017
5cbc76d
improve rte pasting
erquhart Jun 23, 2017
cba631b
improve visual/raw editor consistency
erquhart Jun 27, 2017
5a664f8
remove prosemirror, reuse unified pipelines
erquhart Jun 27, 2017
a8fe57e
pre-process visual editor pastes w/ unified
erquhart Jun 29, 2017
c49d84b
add empty node and Paper emoji unified plugins
erquhart Jul 5, 2017
804ef3d
use true source maps
erquhart Jul 7, 2017
b08a9fc
improve Dropbox Paper paste handling
erquhart Jul 7, 2017
719c105
remove logic from raw markdown editor
erquhart Jul 9, 2017
ae56ef6
convert raw editor to Slate
erquhart Jul 9, 2017
24caead
add list and code toolbar buttons
erquhart Jul 9, 2017
51cd8d3
remove prosemirror dependencies
erquhart Jul 9, 2017
fe3d04b
streamline raw editor pasting
erquhart Jul 10, 2017
f22d09b
add smart soft breaks for visual editor
erquhart Jul 11, 2017
09751ef
allow raw html in markdown
erquhart Jul 12, 2017
0e50210
close blocks on backspace
erquhart Jul 12, 2017
31c9978
fix inline code serializing to blocks
erquhart Jul 12, 2017
63e93d7
improve rte list handling
erquhart Jul 12, 2017
469a50a
add idempotent markdown/html shortcode handling
erquhart Jul 13, 2017
93687d9
add shortcodes through rte toolbar
erquhart Jul 14, 2017
842c293
use mdast instead of html for rte local model
erquhart Jul 18, 2017
c95f061
fix soft break side effects
erquhart Jul 24, 2017
b7379b0
re-implement shortcode parsing to/from mdast
erquhart Jul 24, 2017
dbf14a8
re-enable shortcode insertion via toolbar
erquhart Jul 26, 2017
fbecc88
require images to be parsed as shortcodes
erquhart Jul 26, 2017
6443f5d
allow enter key to make space around void nodes
erquhart Jul 26, 2017
4ac6395
fix focus update on toolbar block click
erquhart Jul 27, 2017
82d9bdd
port history shortcuts from Slate, force focus
erquhart Jul 27, 2017
ae7bd79
re-implement visual editor html paste
erquhart Jul 27, 2017
7a744be
improve list handling
erquhart Jul 27, 2017
de1e361
allow yaml frontmatter parsing
erquhart Jul 27, 2017
28ee67c
eliminate unnecessary editor renders
erquhart Jul 27, 2017
750fbf5
re-implement visual editor link button
erquhart Jul 27, 2017
336cab2
fix html whitespace truncation
erquhart Jul 27, 2017
1f961d3
display images inserted through rte
erquhart Jul 27, 2017
6377d8c
initial refactor, some bugfixes
erquhart Jul 27, 2017
be7385d
refactor remark-shortcodes plugin
erquhart Jul 28, 2017
9174e56
refactor remarkToRehypeShortcodes
erquhart Jul 30, 2017
ca60a6b
update Slate shortcode handling to include paragraph
erquhart Jul 30, 2017
1d65466
improve shortcode handling in visual editor
erquhart Jul 30, 2017
dd51f63
improve visual editor content styling
erquhart Jul 31, 2017
9dcda7b
organize serializers
erquhart Jul 31, 2017
406ae57
add blockquote rte button
erquhart Jul 31, 2017
cf2b7be
refactor and document rte serializers
erquhart Jul 31, 2017
d84b156
update existing serialization tests
erquhart Aug 1, 2017
18b98fc
remove superfluous deps, update yarn.lock
erquhart Aug 1, 2017
2bb6732
fix visual editor heading line height
erquhart Aug 1, 2017
3d83325
add node type check to avoid errors in rte
erquhart Aug 2, 2017
9c0b726
fix small code issues in RTE implementation
erquhart Aug 2, 2017
317a876
fix html paste for visual editor
erquhart Aug 3, 2017
0ea62e0
fix rte pasted links with leading/trailing spaces
erquhart Aug 4, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 23 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,38 +51,38 @@
"devDependencies": {
"babel": "^6.5.2",
"babel-cli": "^6.18.0",
"babel-core": "^6.5.1",
"babel-core": "^6.23.1",
"babel-jest": "^20.0.3",
"babel-loader": "^7.0.0",
"babel-plugin-lodash": "^3.2.0",
"babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0",
"babel-preset-stage-1": "^6.16.0",
"babel-runtime": "^6.5.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-1": "^6.22.0",
"babel-runtime": "^6.23.0",
"cross-env": "^5.0.2",
"css-loader": "^0.28.4",
"enzyme": "^2.4.1",
"eslint": "^3.7.1",
"eslint-config-netlify": "github:netlify/eslint-config-netlify",
"eslint-import-resolver-webpack": "^0.8.3",
"exports-loader": "^0.6.3",
"exports-loader": "^0.6.4",
"extract-text-webpack-plugin": "^2.1.2",
"file-loader": "^0.11.2",
"identity-obj-proxy": "^3.0.0",
"imports-loader": "^0.7.1",
"jest": "^20.0.4",
"jest-cli": "^20.0.4",
"lint-staged": "^3.1.0",
"lint-staged": "^3.3.1",
"node-sass": "^3.10.0",
"npm-check": "^5.2.3",
"postcss-cssnext": "^2.7.0",
"postcss-import": "^10.0.0",
"postcss-loader": "^2.0.5",
"react-addons-test-utils": "^15.3.2",
"react-addons-test-utils": "^15.4.2",
"sass-loader": "^6.0.5",
"style-loader": "^0.18.2",
"stylefmt": "^4.3.1",
"stylelint": "^7.3.1",
"stylelint": "^7.9.0",
"stylelint-config-css-modules": "^0.1.0",
"stylelint-config-standard": "^13.0.2",
"stylelint-declaration-block-order": "^0.1.0",
Expand Down Expand Up @@ -110,27 +110,16 @@
"jwt-decode": "^2.1.0",
"localforage": "^1.4.2",
"lodash": "^4.13.1",
"markup-it": "^2.0.0",
"material-design-icons": "^3.0.1",
"mdast-util-definitions": "^1.2.2",
"mdast-util-to-string": "^1.0.4",
"moment": "^2.11.2",
"netlify-auth-js": "^0.5.5",
"normalize.css": "^4.2.0",
"preliminaries": "1.1.0",
"preliminaries-parser-toml": "1.1.0",
"preliminaries-parser-yaml": "1.1.0",
"prismjs": "^1.5.1",
"prosemirror-commands": "^0.16.0",
"prosemirror-history": "^0.16.0",
"prosemirror-inputrules": "^0.16.0",
"prosemirror-keymap": "^0.16.0",
"prosemirror-markdown": "^0.16.0",
"prosemirror-model": "^0.16.0",
"prosemirror-schema-basic": "^0.16.0",
"prosemirror-schema-list": "^0.16.0",
"prosemirror-schema-table": "^0.16.0",
"prosemirror-state": "^0.16.0",
"prosemirror-transform": "^0.16.0",
"prosemirror-view": "^0.16.0",
"react": "^15.1.0",
"react-addons-css-transition-group": "^15.3.1",
"react-autosuggest": "^7.0.1",
Expand All @@ -157,12 +146,20 @@
"redux-notifications": "^2.1.1",
"redux-optimist": "^0.0.2",
"redux-thunk": "^1.0.3",
"selection-position": "^1.0.0",
"rehype-parse": "^3.1.0",
"rehype-remark": "^2.0.0",
"rehype-stringify": "^3.0.0",
"remark-parse": "^3.0.1",
"remark-rehype": "^2.0.0",
"remark-stringify": "^3.0.1",
"semaphore": "^1.0.5",
"slate": "^0.14.14",
"slate-drop-or-paste-images": "^0.2.0",
"slate": "^0.21.0",
"slate-edit-list": "^0.7.1",
"slate-edit-table": "^0.10.1",
"slug": "^0.9.1",
"textarea-caret-position": "^0.1.1",
"unified": "^6.1.4",
"unist-builder": "^1.0.2",
"unist-util-visit-parents": "^1.1.1",
"uuid": "^2.0.3",
"whatwg-fetch": "^1.0.0"
},
Expand Down
16 changes: 12 additions & 4 deletions src/actions/editorialWorkflow.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,20 +228,28 @@ export function persistUnpublishedEntry(collection, existingUnpublishedEntry) {
if (!entryDraft.get('fieldsErrors').isEmpty()) return Promise.resolve();

const backend = currentBackend(state.config);
const transactionID = uuid.v4();
const assetProxies = entryDraft.get('mediaFiles').map(path => getAsset(state, path));
const entry = entryDraft.get('entry');
const transactionID = uuid.v4();

dispatch(unpublishedEntryPersisting(collection, entry, transactionID));
/**
* Serialize the values of any fields with registered serializers, and
* update the entry and entryDraft with the serialized values.
*/
const serializedData = serializeValues(entryDraft.getIn(['entry', 'data']), collection.get('fields'));
const serializedEntry = entry.set('data', serializedData);
const serializedEntryDraft = entryDraft.set('entry', serializedEntry);

dispatch(unpublishedEntryPersisting(collection, serializedEntry, transactionID));
const persistAction = existingUnpublishedEntry ? backend.persistUnpublishedEntry : backend.persistEntry;
return persistAction.call(backend, state.config, collection, entryDraft, assetProxies.toJS())
return persistAction.call(backend, state.config, collection, serializedEntryDraft, assetProxies.toJS())
.then(() => {
dispatch(notifSend({
message: 'Entry saved',
kind: 'success',
dismissAfter: 4000,
}));
return dispatch(unpublishedEntryPersisted(collection, entry, transactionID));
return dispatch(unpublishedEntryPersisted(collection, serializedEntry, transactionID));
})
.catch((error) => {
dispatch(notifSend({
Expand Down
27 changes: 19 additions & 8 deletions src/actions/entries.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { List } from 'immutable';
import { actions as notifActions } from 'redux-notifications';
import { serializeValues } from '../lib/serializeEntryValues';
import { closeEntry } from './editor';
import { currentBackend } from '../backends/backend';
import { getIntegrationProvider } from '../integrations';
Expand Down Expand Up @@ -216,10 +217,11 @@ export function loadEntry(collection, slug) {
const backend = currentBackend(state.config);
dispatch(entryLoading(collection, slug));
return backend.getEntry(collection, slug)
.then(loadedEntry => (
dispatch(entryLoaded(collection, loadedEntry))
))
.then(loadedEntry => {
return dispatch(entryLoaded(collection, loadedEntry))
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems more verbose to me, and doesn't pass our current eslint config (arrow functions with braces should have parens around the arguments). I prefer the old version, which is simply an expression (in fact, the old version has an extra set of parens that are unneeded).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why I did this, probably converted to run logs for debugging and forgot to switch back.

.catch((error) => {
console.error(error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it provides no stack trace, and doesn't point to anything that's aware of source maps. But it's better than nothing.

dispatch(notifSend({
message: `Failed to load entry: ${ error.message }`,
kind: 'danger',
Expand Down Expand Up @@ -265,28 +267,37 @@ export function persistEntry(collection) {

// Early return if draft contains validation errors
if (!entryDraft.get('fieldsErrors').isEmpty()) return Promise.reject();

const backend = currentBackend(state.config);
const assetProxies = entryDraft.get('mediaFiles').map(path => getAsset(state, path));
const entry = entryDraft.get('entry');
dispatch(entryPersisting(collection, entry));

/**
* Serialize the values of any fields with registered serializers, and
* update the entry and entryDraft with the serialized values.
*/
const serializedData = serializeValues(entryDraft.getIn(['entry', 'data']), collection.get('fields'));
const serializedEntry = entry.set('data', serializedData);
const serializedEntryDraft = entryDraft.set('entry', serializedEntry);
dispatch(entryPersisting(collection, serializedEntry));
return backend
.persistEntry(state.config, collection, entryDraft, assetProxies.toJS())
.persistEntry(state.config, collection, serializedEntryDraft, assetProxies.toJS())
.then(() => {
dispatch(notifSend({
message: 'Entry saved',
kind: 'success',
dismissAfter: 4000,
}));
return dispatch(entryPersisted(collection, entry));
return dispatch(entryPersisted(collection, serializedEntry));
})
.catch((error) => {
console.error(error);
dispatch(notifSend({
message: `Failed to persist entry: ${ error }`,
kind: 'danger',
dismissAfter: 8000,
}));
return dispatch(entryPersistFail(collection, entry, error));
return dispatch(entryPersistFail(collection, serializedEntry, error));
});
};
}
Expand Down
10 changes: 8 additions & 2 deletions src/components/ControlPanel/ControlPane.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

& input,
& textarea,
& select {
font-family: 'SFMono-Regular', Consolas, "Liberation Mono", Menlo, Courier, monospace;
& select,
& div[contenteditable=true] {
display: block;
width: 100%;
padding: 12px;
Expand All @@ -28,6 +28,12 @@
border-color: var(--primaryColor);
}
}

& input,
& textarea,
& select {
font-family: var(--fontFamilyMono);
}
}

.label {
Expand Down
Loading