forked from WordPress/gutenberg
/
factory.js
118 lines (102 loc) · 3.47 KB
/
factory.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
* External dependencies
*/
import uuid from 'uuid/v4';
import {
get,
reduce,
castArray,
findIndex,
isObjectLike,
find,
} from 'lodash';
/**
* Internal dependencies
*/
import { getBlockType } from './registration';
/**
* Returns a block object given its type and attributes.
*
* @param {String} name Block name
* @param {Object} blockAttributes Block attributes
* @return {Object} Block object
*/
export function createBlock( name, blockAttributes = {} ) {
// Get the type definition associated with a registered block.
const blockType = getBlockType( name );
// Ensure attributes contains only values defined by block type, and merge
// default values for missing attributes.
const attributes = reduce( blockType.attributes, ( result, source, key ) => {
const value = blockAttributes[ key ];
if ( undefined !== value ) {
result[ key ] = value;
} else if ( source.default ) {
result[ key ] = source.default;
}
return result;
}, {} );
// Keep the anchor if the block supports it
if ( blockType.supportAnchor && blockAttributes.anchor ) {
attributes.anchor = blockAttributes.anchor;
}
// Keep the className if the block supports it
if ( blockType.className !== false && blockAttributes.className ) {
attributes.className = blockAttributes.className;
}
// Blocks are stored with a unique ID, the assigned type name,
// and the block attributes.
return {
uid: uuid(),
name,
isValid: true,
attributes,
};
}
/**
* Switch a block into one or more blocks of the new block type.
*
* @param {Object} block Block object
* @param {string} name Block name
* @return {Array} Block object
*/
export function switchToBlockType( block, name ) {
// Find the right transformation by giving priority to the "to"
// transformation.
const destinationType = getBlockType( name );
const sourceType = getBlockType( block.name );
const transformationsFrom = get( destinationType, 'transforms.from', [] );
const transformationsTo = get( sourceType, 'transforms.to', [] );
const transformation =
find( transformationsTo, t => t.type === 'block' && t.blocks.indexOf( name ) !== -1 ) ||
find( transformationsFrom, t => t.type === 'block' && t.blocks.indexOf( block.name ) !== -1 );
// Stop if there is no valid transformation. (How did we get here?)
if ( ! transformation ) {
return null;
}
let transformationResults = transformation.transform( block.attributes );
// Ensure that the transformation function returned an object or an array
// of objects.
if ( ! isObjectLike( transformationResults ) ) {
return null;
}
// If the transformation function returned a single object, we want to work
// with an array instead.
transformationResults = castArray( transformationResults );
// Ensure that every block object returned by the transformation has a
// valid block type.
if ( transformationResults.some( ( result ) => ! getBlockType( result.name ) ) ) {
return null;
}
const firstSwitchedBlock = findIndex( transformationResults, ( result ) => result.name === name );
// Ensure that at least one block object returned by the transformation has
// the expected "destination" block type.
if ( firstSwitchedBlock < 0 ) {
return null;
}
return transformationResults.map( ( result, index ) => ( {
...result,
// The first transformed block whose type matches the "destination"
// type gets to keep the existing block's UID.
uid: index === firstSwitchedBlock ? block.uid : result.uid,
} ) );
}