Skip to content

Commit

Permalink
Memoize getInserterItems()
Browse files Browse the repository at this point in the history
Use createSelector() to cache the results of getInserterItems() and
increase inserter performance.
  • Loading branch information
noisysocks committed May 7, 2018
1 parent 9110e88 commit 5950a15
Showing 1 changed file with 139 additions and 129 deletions.
268 changes: 139 additions & 129 deletions editor/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1235,154 +1235,164 @@ function getInsertUsage( state, id ) {
* @property {number} frecency Hueristic that combines recency and frecency. Useful for
* ordering items by relevancy.
*/
export function getInserterItems( state, editorAllowedBlockTypes, parentUID = null ) {
const editorAllowList = parseAllowList( editorAllowedBlockTypes );

let parentAllowList, parentName;
if ( parentUID ) {
const parentBlockListSettings = getBlockListSettings( state, parentUID );
const parentAllowedBlockTypes = get( parentBlockListSettings, [ 'supportedBlocks' ] );
parentAllowList = parseAllowList( parentAllowedBlockTypes );
parentName = getBlockName( state, parentUID );
} else {
parentAllowList = parseAllowList( true );
parentName = getCurrentPostType( state );
}

const calculateUtility = ( category, count, isContextual ) => {
if ( isContextual ) {
return 3;
} else if ( count > 0 ) {
return 2;
} else if ( category === 'common' ) {
return 1;
}
return 0;
};

const calculateFrecency = ( time, count ) => {
if ( ! time ) {
return count;
}

const duration = Date.now() - time;
switch ( true ) {
case duration < 3600:
return count * 4;
case duration < ( 24 * 3600 ):
return count * 2;
case duration < ( 7 * 24 * 3600 ):
return count / 2;
default:
return count / 4;
}
};

const canInsertBlockType = ( blockType ) => {
const isAllowedInEditor = editorAllowList[ blockType.name ] || editorAllowList[ '*' ];
if ( ! isAllowedInEditor ) {
return false;
}

if ( blockType.name in parentAllowList ) {
return parentAllowList[ blockType.name ];
export const getInserterItems = createSelector(
( state, editorAllowedBlockTypes, parentUID = null ) => {
const editorAllowList = parseAllowList( editorAllowedBlockTypes );

let parentAllowList, parentName;
if ( parentUID ) {
const parentBlockListSettings = getBlockListSettings( state, parentUID );
const parentAllowedBlockTypes = get( parentBlockListSettings, [ 'supportedBlocks' ] );
parentAllowList = parseAllowList( parentAllowedBlockTypes );
parentName = getBlockName( state, parentUID );
} else {
parentAllowList = parseAllowList( true );
parentName = getCurrentPostType( state );
}

const blockAllowList = parseAllowList( blockType.allowedParents );

if ( parentName in blockAllowList ) {
return blockAllowList[ parentName ];
}
const calculateUtility = ( category, count, isContextual ) => {
if ( isContextual ) {
return 3;
} else if ( count > 0 ) {
return 2;
} else if ( category === 'common' ) {
return 1;
}
return 0;
};

return parentAllowList[ '*' ] && blockAllowList[ '*' ];
};
const calculateFrecency = ( time, count ) => {
if ( ! time ) {
return count;
}

const duration = Date.now() - time;
switch ( true ) {
case duration < 3600:
return count * 4;
case duration < ( 24 * 3600 ):
return count * 2;
case duration < ( 7 * 24 * 3600 ):
return count / 2;
default:
return count / 4;
}
};

const buildBlockTypeInserterItem = ( blockType ) => {
const id = blockType.name;
const canInsertBlockType = ( blockType ) => {
const isAllowedInEditor = editorAllowList[ blockType.name ] || editorAllowList[ '*' ];
if ( ! isAllowedInEditor ) {
return false;
}

let isDisabled = false;
if ( blockType.useOnce ) {
isDisabled = getBlocks( state ).some( ( block ) => block.name === blockType.name );
}
if ( blockType.name in parentAllowList ) {
return parentAllowList[ blockType.name ];
}

const blockAllowList = parseAllowList( blockType.allowedParents );
const isContextual = blockType.name in parentAllowList || parentName in blockAllowList;
const blockAllowList = parseAllowList( blockType.allowedParents );

const { time, count } = getInsertUsage( state, id );
const utility = calculateUtility( blockType.category, count, isContextual );
const frecency = calculateFrecency( time, count );
if ( parentName in blockAllowList ) {
return blockAllowList[ parentName ];
}

return {
id,
name: blockType.name,
initialAttributes: {},
title: blockType.title,
icon: blockType.icon,
category: blockType.category,
keywords: blockType.keywords,
isDisabled,
utility,
frecency,
return parentAllowList[ '*' ] && blockAllowList[ '*' ];
};
};

const canInsertSharedBlock = ( sharedBlock ) => {
const isAllowedInEditor = editorAllowList[ 'core/block' ] || editorAllowList[ '*' ];
if ( ! isAllowedInEditor ) {
return false;
}

const isAllowedInParent = parentAllowList[ 'core/block' ] || parentAllowList[ '*' ];
if ( ! isAllowedInParent ) {
return false;
}

const referencedBlock = getBlock( state, sharedBlock.uid );
if ( ! referencedBlock ) {
return false;
}
const buildBlockTypeInserterItem = ( blockType ) => {
const id = blockType.name;

let isDisabled = false;
if ( blockType.useOnce ) {
isDisabled = getBlocks( state ).some( ( block ) => block.name === blockType.name );
}

const blockAllowList = parseAllowList( blockType.allowedParents );
const isContextual = blockType.name in parentAllowList || parentName in blockAllowList;

const { time, count } = getInsertUsage( state, id );
const utility = calculateUtility( blockType.category, count, isContextual );
const frecency = calculateFrecency( time, count );

return {
id,
name: blockType.name,
initialAttributes: {},
title: blockType.title,
icon: blockType.icon,
category: blockType.category,
keywords: blockType.keywords,
isDisabled,
utility,
frecency,
};
};

const referencedBlockType = getBlockType( referencedBlock.name );
if ( ! referencedBlockType ) {
return false;
}
const canInsertSharedBlock = ( sharedBlock ) => {
const isAllowedInEditor = editorAllowList[ 'core/block' ] || editorAllowList[ '*' ];
if ( ! isAllowedInEditor ) {
return false;
}

if ( ! canInsertBlockType( referencedBlockType ) ) {
return false;
}
const isAllowedInParent = parentAllowList[ 'core/block' ] || parentAllowList[ '*' ];
if ( ! isAllowedInParent ) {
return false;
}

return true;
};
const referencedBlock = getBlock( state, sharedBlock.uid );
if ( ! referencedBlock ) {
return false;
}

const buildSharedBlockInserterItem = ( sharedBlock ) => {
const id = `core/block/${ sharedBlock.id }`;
const referencedBlockType = getBlockType( referencedBlock.name );
if ( ! referencedBlockType ) {
return false;
}

const referencedBlock = getBlock( state, sharedBlock.uid );
const referencedBlockType = getBlockType( referencedBlock.name );
if ( ! canInsertBlockType( referencedBlockType ) ) {
return false;
}

const { time, count } = getInsertUsage( state, id );
const utility = calculateUtility( 'shared', count, false );
const frecency = calculateFrecency( time, count );
return true;
};

return {
id,
name: 'core/block',
initialAttributes: { ref: sharedBlock.id },
title: sharedBlock.title,
icon: referencedBlockType.icon,
category: 'shared',
keywords: [],
isDisabled: false,
utility,
frecency,
const buildSharedBlockInserterItem = ( sharedBlock ) => {
const id = `core/block/${ sharedBlock.id }`;

const referencedBlock = getBlock( state, sharedBlock.uid );
const referencedBlockType = getBlockType( referencedBlock.name );

const { time, count } = getInsertUsage( state, id );
const utility = calculateUtility( 'shared', count, false );
const frecency = calculateFrecency( time, count );

return {
id,
name: 'core/block',
initialAttributes: { ref: sharedBlock.id },
title: sharedBlock.title,
icon: referencedBlockType.icon,
category: 'shared',
keywords: [],
isDisabled: false,
utility,
frecency,
};
};
};

return [
...getBlockTypes().filter( canInsertBlockType ).map( buildBlockTypeInserterItem ),
...getSharedBlocks( state ).filter( canInsertSharedBlock ).map( buildSharedBlockInserterItem ),
];
}
return [
...getBlockTypes().filter( canInsertBlockType ).map( buildBlockTypeInserterItem ),
...getSharedBlocks( state ).filter( canInsertSharedBlock ).map( buildSharedBlockInserterItem ),
];
},
( state, editorAllowedBlockTypes, parentUID ) => [
state.editor.present.blockOrder,
state.editor.present.blocksByUid,
state.sharedBlocks.data,
state.currentPost.type,
state.blockListSettings[ parentUID ],
state.preferences.insertUsage,
],
);

/**
* Returns a list of items which the user is likely to want to insert. These
Expand Down

0 comments on commit 5950a15

Please sign in to comment.