Skip to content

Commit

Permalink
Move registering tokens to store init
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Jun 25, 2018
1 parent c10ba5e commit 0fabb77
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 103 deletions.
23 changes: 2 additions & 21 deletions editor/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
defer,
noop,
reject,
forOwn,
} from 'lodash';
import 'element-closest';

Expand All @@ -28,7 +27,7 @@ import {
import { createBlobURL } from '@wordpress/blob';
import { keycodes } from '@wordpress/utils';
import { withInstanceId, withSafeTimeout, Slot } from '@wordpress/components';
import { withSelect, withDispatch } from '@wordpress/data';
import { withSelect } from '@wordpress/data';
import { rawHandler } from '@wordpress/blocks';

/**
Expand All @@ -43,7 +42,6 @@ import { pickAriaProps } from './aria';
import patterns from './patterns';
import { withBlockEditContext } from '../block-edit/context';
import { domToFormat, valueToString } from './format';
import * as tokens from './core-tokens';
import TokenUI from './tokens/ui';

const { BACKSPACE, DELETE, ENTER, rawShortcut } = keycodes;
Expand Down Expand Up @@ -105,10 +103,8 @@ export function getFormatProperties( formatName, parents ) {

const DEFAULT_FORMATS = [ 'bold', 'italic', 'strikethrough', 'link', 'code' ];

let coreTokensRegistered = false;

export class RichText extends Component {
constructor( { registerToken } ) {
constructor() {
super( ...arguments );

this.onInit = this.onInit.bind( this );
Expand All @@ -133,14 +129,6 @@ export class RichText extends Component {
};

this.containerRef = createRef();

if ( ! coreTokensRegistered ) {
forOwn( tokens, ( { name, settings } ) => {
registerToken( name, settings );
} );

coreTokensRegistered = true;
}
}

/**
Expand Down Expand Up @@ -982,13 +970,6 @@ const RichTextContainer = compose( [
isViewportSmall: isViewportMatch( '< small' ),
};
} ),
withDispatch( ( dispatch ) => {
const { registerToken } = dispatch( 'core/editor' );

return {
registerToken,
};
} ),
withSafeTimeout,
] )( RichText );

Expand Down
96 changes: 96 additions & 0 deletions editor/components/rich-text/tokens/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* External dependencies
*/
import { has, isFunction } from 'lodash';

/**
* WordPress dependencies
*/
import { isValidIcon, normalizeIconObject } from '@wordpress/blocks';
import { applyFilters } from '@wordpress/hooks';

/**
* Browser dependencies
*/
const { error } = window.console;

/**
* Validates the token settings object.
*
* @param {string} name Token name.
* @param {Object} settings Token settings.
* @param {Object} state core/editor state.
*
* @return {Object} Validated token settings.
*/
export function validateTokenSettings( name, settings, state ) {
if ( typeof name !== 'string' ) {
error(
'Token names must be strings.'
);
return;
}

if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( name ) ) {
error(
'Token names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-token'
);
return;
}

if ( has( state, [ name ] ) ) {
error(
'Token "' + name + '" is already registered.'
);
return;
}

settings = applyFilters( 'editor.registerToken', settings, name );

if ( ! settings || ! isFunction( settings.save ) ) {
error(
'The "save" property must be specified and must be a valid function.'
);
return;
}

if ( has( settings, [ 'edit' ] ) && ! isFunction( settings.edit ) ) {
error(
'The "edit" property must be a valid function.'
);
return;
}

if ( has( settings, [ 'keywords' ] ) && settings.keywords.length > 3 ) {
error(
'The token "' + name + '" can have a maximum of 3 keywords.'
);
return;
}

if ( ! has( settings, [ 'title' ] ) || settings.title === '' ) {
error(
'The token "' + name + '" must have a title.'
);
return;
}

if ( typeof settings.title !== 'string' ) {
error(
'Token titles must be strings.'
);
return;
}

settings.icon = normalizeIconObject( settings.icon );

if ( ! isValidIcon( settings.icon.src ) ) {
error(
'The icon passed is invalid. ' +
'The icon should be a string, an element, a function, or an object following the specifications documented in https://wordpress.org/gutenberg/handbook/block-api/#icon-optional'
);
return;
}

return settings;
}
15 changes: 15 additions & 0 deletions editor/store/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External Dependencies
*/
import { forOwn } from 'lodash';

/**
* WordPress Dependencies
*/
Expand All @@ -16,6 +21,8 @@ import reducer from './reducer';
import applyMiddlewares from './middlewares';
import * as selectors from './selectors';
import * as actions from './actions';
import * as tokens from '../components/rich-text/core-tokens';
import { validateTokenSettings } from '../components/rich-text/tokens';

/**
* Module Constants
Expand All @@ -31,4 +38,12 @@ loadAndPersist( store, reducer, 'preferences', STORAGE_KEY );
registerSelectors( MODULE_KEY, selectors );
registerActions( MODULE_KEY, actions );

forOwn( tokens, ( { name, settings } ) => {
settings = validateTokenSettings( name, settings, store.getState() );

if ( settings ) {
store.dispatch( actions.registerToken( name, settings ) );
}
} );

export default store;
85 changes: 3 additions & 82 deletions editor/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@ import {
includes,
overSome,
get,
has,
isFunction,
} from 'lodash';

/**
* WordPress dependencies
*/
import { isSharedBlock, isValidIcon, normalizeIconObject } from '@wordpress/blocks';
import { isSharedBlock } from '@wordpress/blocks';
import { combineReducers } from '@wordpress/data';
import { applyFilters } from '@wordpress/hooks';

/**
* Internal dependencies
Expand All @@ -37,11 +34,6 @@ import withChangeDetection from '../utils/with-change-detection';
import { PREFERENCES_DEFAULTS, EDITOR_SETTINGS_DEFAULTS } from './defaults';
import { insertAt, moveTo } from './array';

/**
* Browser dependencies
*/
const { error } = window.console;

/**
* Returns a post attribute value, flattening nested rendered content using its
* raw value in place of its original object form.
Expand Down Expand Up @@ -1114,82 +1106,11 @@ export function autosave( state = null, action ) {
*/
export function tokens( state = {}, action ) {
switch ( action.type ) {
case 'REGISTER_TOKEN': {
const { name } = action;

if ( typeof name !== 'string' ) {
error(
'Token names must be strings.'
);
return state;
}

if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( name ) ) {
error(
'Token names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-token'
);
return state;
}

if ( has( state, [ name ] ) ) {
error(
'Token "' + name + '" is already registered.'
);
return state;
}

const tokenSettings = applyFilters( 'editor.registerToken', action.settings, name );

if ( ! tokenSettings || ! isFunction( tokenSettings.save ) ) {
error(
'The "save" property must be specified and must be a valid function.'
);
return state;
}

if ( has( tokenSettings, [ 'edit' ] ) && ! isFunction( tokenSettings.edit ) ) {
error(
'The "edit" property must be a valid function.'
);
return state;
}

if ( has( tokenSettings, [ 'keywords' ] ) && tokenSettings.keywords.length > 3 ) {
error(
'The token "' + name + '" can have a maximum of 3 keywords.'
);
return state;
}

if ( ! has( tokenSettings, [ 'title' ] ) || tokenSettings.title === '' ) {
error(
'The token "' + name + '" must have a title.'
);
return state;
}

if ( typeof tokenSettings.title !== 'string' ) {
error(
'Token titles must be strings.'
);
return state;
}

tokenSettings.icon = normalizeIconObject( tokenSettings.icon );

if ( ! isValidIcon( tokenSettings.icon.src ) ) {
error(
'The icon passed is invalid. ' +
'The icon should be a string, an element, a function, or an object following the specifications documented in https://wordpress.org/gutenberg/handbook/block-api/#icon-optional'
);
return state;
}

case 'REGISTER_TOKEN':
return {
...state,
[ name ]: tokenSettings,
[ action.name ]: action.settings,
};
}
case 'UNREGISTER_TOKEN':
return omit( state, action.name );
}
Expand Down

0 comments on commit 0fabb77

Please sign in to comment.