Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Feb 8, 2018
1 parent f99b3a7 commit a2b08be
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 231 deletions.
77 changes: 30 additions & 47 deletions blocks/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,10 @@ export default class RichText extends Component {
this.onKeyUp = this.onKeyUp.bind( this );
this.changeFormats = this.changeFormats.bind( this );
this.onSelectionChange = this.onSelectionChange.bind( this );
this.maybePropagateUndo = this.maybePropagateUndo.bind( this );
this.onPropagateUndo = this.onPropagateUndo.bind( this );
this.onPastePreProcess = this.onPastePreProcess.bind( this );
this.onPaste = this.onPaste.bind( this );
this.onAddUndo = this.onAddUndo.bind( this );

this.state = {
formats: {},
Expand Down Expand Up @@ -140,15 +141,16 @@ export default class RichText extends Component {
} );

editor.on( 'init', this.onInit );
editor.on( 'focusout', this.onChange );
editor.on( 'NewBlock', this.onNewBlock );
editor.on( 'nodechange', this.onNodeChange );
editor.on( 'keydown', this.onKeyDown );
editor.on( 'keyup', this.onKeyUp );
editor.on( 'selectionChange', this.onSelectionChange );
editor.on( 'BeforeExecCommand', this.maybePropagateUndo );
editor.on( 'BeforeExecCommand', this.onPropagateUndo );
editor.on( 'PastePreProcess', this.onPastePreProcess, true /* Add before core handlers */ );
editor.on( 'paste', this.onPaste, true /* Add before core handlers */ );
editor.on( 'input', this.onChange );
editor.on( 'addundo', this.onAddUndo );

patterns.apply( this, [ editor ] );

Expand Down Expand Up @@ -220,23 +222,15 @@ export default class RichText extends Component {
/**
* Handles an undo event from tinyMCE.
*
* When user attempts Undo when empty Undo stack, propagate undo
* action to context handler. The compromise here is that: TinyMCE
* handles Undo until change, at which point `editor.save` resets
* history. If no history exists, let context handler have a turn.
* Defer in case an immediate undo causes TinyMCE to be destroyed,
* if other undo behaviors test presence of an input field.
*
* @param {UndoEvent} event The undo event as triggered by tinyMCE.
* @param {UndoEvent} event The undo event as triggered by TinyMCE.
*/
maybePropagateUndo( event ) {
onPropagateUndo( event ) {
const { onUndo } = this.context;
if ( onUndo && event.command === 'Undo' && ! this.editor.undoManager.hasUndo() ) {
defer( onUndo );
const { command } = event;

// We could return false here to stop other TinyMCE event handlers
// from running, but we assume TinyMCE won't do anything on an
// empty undo stack anyways.
if ( onUndo && ( command === 'Undo' || command === 'Redo' ) ) {
defer( onUndo );
event.preventDefault();
}
}

Expand Down Expand Up @@ -358,21 +352,21 @@ export default class RichText extends Component {
}
}

fireChange() {
this.savedContent = this.getContent();
this.editor.save();
this.props.onChange( this.state.empty ? [] : this.savedContent );
}

/**
* Handles any case where the content of the tinyMCE instance has changed.
*/
onChange() {
// Note that due to efficiency, speed and low cost requirements isDirty may
// not reflect reality for a brief period immediately after a change.
if ( this.editor.isDirty() ) {
this.fireChange();
this.savedContent = this.getContent();
this.props.onChange( this.state.empty ? [] : this.savedContent );
}

onAddUndo( { lastLevel } ) {
if ( ! lastLevel ) {
return;
}

this.onChange();
this.context.onCreateUndoLevel();
}

/**
Expand Down Expand Up @@ -500,7 +494,7 @@ export default class RichText extends Component {
return;
}

this.fireChange();
this.context.onCreateUndoLevel();

const forward = event.keyCode === DELETE;

Expand Down Expand Up @@ -558,6 +552,8 @@ export default class RichText extends Component {
this.splitContent();
}
}

this.context.onCreateUndoLevel();
}
}

Expand Down Expand Up @@ -679,24 +675,8 @@ export default class RichText extends Component {
this.setState( { formats, focusPosition, selectedNodeId: this.state.selectedNodeId + 1 } );
}

updateContent() {
const bookmark = this.editor.selection.getBookmark( 2, true );
this.savedContent = this.props.value;
this.setContent( this.savedContent );
this.editor.selection.moveToBookmark( bookmark );

// Saving the editor on updates avoid unecessary onChanges calls
// These calls can make the focus jump
this.editor.save();
}

setContent( content ) {
if ( ! content ) {
content = '';
}

content = renderToString( content );
this.editor.setContent( content );
setContent( content = '' ) {
this.editor.setContent( renderToString( content ) );
}

getContent() {
Expand All @@ -705,6 +685,7 @@ export default class RichText extends Component {

componentWillUnmount() {
this.onChange();
this.context.onCreateUndoLevel();
}

componentDidUpdate( prevProps ) {
Expand All @@ -716,7 +697,8 @@ export default class RichText extends Component {
! isEqual( this.props.value, prevProps.value ) &&
! isEqual( this.props.value, this.savedContent )
) {
this.updateContent();
this.savedContent = this.props.value;
this.setContent( this.savedContent );
}
}

Expand Down Expand Up @@ -849,6 +831,7 @@ export default class RichText extends Component {
RichText.contextTypes = {
onUndo: noop,
canUserUseUnfilteredHTML: noop,
onCreateUndoLevel: noop,
};

RichText.defaultProps = {
Expand Down
1 change: 1 addition & 0 deletions blocks/rich-text/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class RichTextProvider extends Component {

RichTextProvider.childContextTypes = {
onUndo: noop,
onCreateUndoLevel: noop,
};

export default RichTextProvider;
4 changes: 3 additions & 1 deletion editor/components/provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
/**
* Internal Dependencies
*/
import { setupEditor, undo, initializeMetaBoxState } from '../../store/actions';
import { setupEditor, undo, createUndoLevel, initializeMetaBoxState } from '../../store/actions';
import store from '../../store';

/**
Expand Down Expand Up @@ -105,10 +105,12 @@ class EditorProvider extends Component {
// RichText provider:
//
// - context.onUndo
// - context.onCreateUndoLevel
[
RichTextProvider,
bindActionCreators( {
onUndo: undo,
onCreateUndoLevel: createUndoLevel,
}, this.store.dispatch ),
],

Expand Down
4 changes: 4 additions & 0 deletions editor/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,10 @@ export function undo() {
return { type: 'UNDO' };
}

export function createUndoLevel() {
return { type: 'CREATE_UNDO_LEVEL' };
}

/**
* Returns an action object used in signalling that the blocks
* corresponding to the specified UID set are to be removed.
Expand Down
41 changes: 21 additions & 20 deletions editor/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export function getCurrentPostLastRevisionId( state ) {
* @return {Object} Object of key value pairs comprising unsaved edits.
*/
export function getPostEdits( state ) {
return get( state, [ 'editor', 'present', 'edits' ], {} );
return get( state, [ 'editor', 'buffer', 'edits' ], {} );
}

/**
Expand Down Expand Up @@ -368,9 +368,10 @@ export function getDocumentTitle( state ) {
* @return {string} Raw post excerpt.
*/
export function getEditedPostExcerpt( state ) {
return state.editor.present.edits.excerpt === undefined ?
const edits = getPostEdits( state );
return edits.excerpt === undefined ?
state.currentPost.excerpt :
state.editor.present.edits.excerpt;
edits.excerpt;
}

/**
Expand Down Expand Up @@ -402,7 +403,7 @@ export function getEditedPostPreviewLink( state ) {
*/
export const getBlock = createSelector(
( state, uid ) => {
const block = state.editor.present.blocksByUid[ uid ];
const block = state.editor.buffer.blocksByUid[ uid ];
if ( ! block ) {
return null;
}
Expand Down Expand Up @@ -435,15 +436,15 @@ export const getBlock = createSelector(
};
},
( state ) => [
get( state, [ 'editor', 'present', 'blocksByUid' ] ),
get( state, [ 'editor', 'present', 'edits', 'meta' ] ),
get( state, [ 'editor', 'buffer', 'blocksByUid' ] ),
get( state, [ 'editor', 'buffer', 'edits', 'meta' ] ),
get( state, 'currentPost.meta' ),
]
);

function getPostMeta( state, key ) {
return has( state, [ 'editor', 'present', 'edits', 'meta', key ] ) ?
get( state, [ 'editor', 'present', 'edits', 'meta', key ] ) :
return has( state, [ 'editor', 'buffer', 'edits', 'meta', key ] ) ?
get( state, [ 'editor', 'buffer', 'edits', 'meta', key ] ) :
get( state, [ 'currentPost', 'meta', key ] );
}

Expand All @@ -465,8 +466,8 @@ export const getBlocks = createSelector(
);
},
( state ) => [
state.editor.present.blockOrder,
state.editor.present.blocksByUid,
state.editor.buffer.blockOrder,
state.editor.buffer.blocksByUid,
]
);

Expand Down Expand Up @@ -525,7 +526,7 @@ export function getSelectedBlock( state ) {
* @return {?string} Root UID, if exists
*/
export function getBlockRootUID( state, uid ) {
const { blockOrder } = state.editor.present;
const { blockOrder } = state.editor.buffer;

for ( const rootUID in blockOrder ) {
if ( includes( blockOrder[ rootUID ], uid ) ) {
Expand Down Expand Up @@ -574,7 +575,7 @@ export function getAdjacentBlock( state, startUID, modifier = 1 ) {
return null;
}

const { blockOrder } = state.editor.present;
const { blockOrder } = state.editor.buffer;
const orderSet = blockOrder[ rootUID ];
const index = orderSet.indexOf( startUID );
const nextIndex = ( index + ( 1 * modifier ) );
Expand Down Expand Up @@ -670,7 +671,7 @@ export const getMultiSelectedBlockUids = createSelector(
return blockOrder.slice( startIndex, endIndex + 1 );
},
( state ) => [
state.editor.present.blockOrder,
state.editor.buffer.blockOrder,
state.blockSelection.start,
state.blockSelection.end,
],
Expand All @@ -687,11 +688,11 @@ export const getMultiSelectedBlockUids = createSelector(
export const getMultiSelectedBlocks = createSelector(
( state ) => getMultiSelectedBlockUids( state ).map( ( uid ) => getBlock( state, uid ) ),
( state ) => [
state.editor.present.blockOrder,
state.editor.buffer.blockOrder,
state.blockSelection.start,
state.blockSelection.end,
state.editor.present.blocksByUid,
state.editor.present.edits.meta,
state.editor.buffer.blocksByUid,
state.editor.buffer.edits.meta,
state.currentPost.meta,
]
);
Expand Down Expand Up @@ -797,7 +798,7 @@ export function getMultiSelectedBlocksEndUid( state ) {
* @return {Array} Ordered unique IDs of post blocks.
*/
export function getBlockOrder( state, rootUID ) {
return state.editor.present.blockOrder[ rootUID || '' ] || DEFAULT_BLOCK_ORDER;
return state.editor.buffer.blockOrder[ rootUID || '' ] || DEFAULT_BLOCK_ORDER;
}

/**
Expand Down Expand Up @@ -1049,9 +1050,9 @@ export const getEditedPostContent = createSelector(
return serialize( getBlocks( state ) );
},
( state ) => [
state.editor.present.edits.content,
state.editor.present.blocksByUid,
state.editor.present.blockOrder,
state.editor.buffer.edits.content,
state.editor.buffer.blocksByUid,
state.editor.buffer.blockOrder,
],
);

Expand Down
Loading

0 comments on commit a2b08be

Please sign in to comment.