2
2
* External dependencies
3
3
*/
4
4
import classnames from 'classnames' ;
5
- import { forEach , last } from 'lodash' ;
5
+ import { last , isEqual } from 'lodash' ;
6
6
import { Parser as HtmlToReactParser } from 'html-to-react' ;
7
+ import { Fill } from 'react-slot-fill' ;
7
8
8
9
/**
9
10
* Internal dependencies
10
11
*/
11
12
import './style.scss' ;
12
13
14
+ // TODO: We mustn't import by relative path traversing from blocks to editor
15
+ // as we're doing here; instead, we should consider a common components path.
16
+ import Toolbar from '../../../editor/components/toolbar' ;
17
+
13
18
const htmlToReactParser = new HtmlToReactParser ( ) ;
14
19
const formatMap = {
15
20
strong : 'bold' ,
16
21
em : 'italic' ,
17
22
del : 'strikethrough'
18
23
} ;
19
24
25
+ const formattingControls = [
26
+ {
27
+ icon : 'editor-bold' ,
28
+ title : wp . i18n . __ ( 'Bold' ) ,
29
+ format : 'bold'
30
+ } ,
31
+ {
32
+ icon : 'editor-italic' ,
33
+ title : wp . i18n . __ ( 'Italic' ) ,
34
+ format : 'italic'
35
+ } ,
36
+ {
37
+ icon : 'editor-strikethrough' ,
38
+ title : wp . i18n . __ ( 'Strikethrough' ) ,
39
+ format : 'strikethrough'
40
+ }
41
+ ] ;
42
+
20
43
export default class Editable extends wp . element . Component {
21
44
constructor ( ) {
22
45
super ( ...arguments ) ;
46
+
23
47
this . onInit = this . onInit . bind ( this ) ;
24
48
this . onSetup = this . onSetup . bind ( this ) ;
25
49
this . onChange = this . onChange . bind ( this ) ;
26
50
this . onNewBlock = this . onNewBlock . bind ( this ) ;
27
- this . bindNode = this . bindNode . bind ( this ) ;
51
+ this . bindEditorNode = this . bindEditorNode . bind ( this ) ;
28
52
this . onFocus = this . onFocus . bind ( this ) ;
29
53
this . onNodeChange = this . onNodeChange . bind ( this ) ;
30
- this . formats = { } ;
54
+
55
+ this . state = {
56
+ formats : { }
57
+ } ;
31
58
}
32
59
33
60
componentDidMount ( ) {
@@ -36,7 +63,7 @@ export default class Editable extends wp.element.Component {
36
63
37
64
initialize ( ) {
38
65
const config = {
39
- target : this . node ,
66
+ target : this . editorNode ,
40
67
theme : false ,
41
68
inline : true ,
42
69
toolbar : false ,
@@ -57,10 +84,7 @@ export default class Editable extends wp.element.Component {
57
84
editor . on ( 'focusout' , this . onChange ) ;
58
85
editor . on ( 'NewBlock' , this . onNewBlock ) ;
59
86
editor . on ( 'focusin' , this . onFocus ) ;
60
-
61
- if ( this . props . onFormatChange ) {
62
- editor . on ( 'nodechange' , this . onNodeChange ) ;
63
- }
87
+ editor . on ( 'nodechange' , this . onNodeChange ) ;
64
88
}
65
89
66
90
onInit ( ) {
@@ -131,7 +155,7 @@ export default class Editable extends wp.element.Component {
131
155
}
132
156
133
157
onNodeChange ( { parents } ) {
134
- this . formats = parents . reduce ( ( result , node ) => {
158
+ const formats = parents . reduce ( ( result , node ) => {
135
159
const tag = node . nodeName . toLowerCase ( ) ;
136
160
137
161
if ( formatMap . hasOwnProperty ( tag ) ) {
@@ -141,11 +165,13 @@ export default class Editable extends wp.element.Component {
141
165
return result ;
142
166
} , { } ) ;
143
167
144
- this . props . onFormatChange ( this . formats ) ;
168
+ if ( ! isEqual ( this . state . formats , formats ) ) {
169
+ this . setState ( { formats } ) ;
170
+ }
145
171
}
146
172
147
- bindNode ( ref ) {
148
- this . node = ref ;
173
+ bindEditorNode ( ref ) {
174
+ this . editorNode = ref ;
149
175
}
150
176
151
177
updateContent ( ) {
@@ -208,31 +234,46 @@ export default class Editable extends wp.element.Component {
208
234
}
209
235
}
210
236
211
- componentWillReceiveProps ( nextProps ) {
212
- forEach ( nextProps . formats , ( state , format ) => {
213
- const currentState = this . formats [ format ] || false ;
237
+ isFormatActive ( format ) {
238
+ return ! ! this . state . formats [ format ] ;
239
+ }
214
240
215
- if ( state !== currentState ) {
216
- this . editor . focus ( ) ;
241
+ toggleFormat ( format ) {
242
+ this . editor . focus ( ) ;
217
243
218
- if ( state ) {
219
- this . editor . formatter . apply ( format ) ;
220
- } else {
221
- this . editor . formatter . remove ( format ) ;
222
- }
223
- }
224
- } ) ;
244
+ if ( this . isFormatActive ( format ) ) {
245
+ this . editor . formatter . remove ( format ) ;
246
+ } else {
247
+ this . editor . formatter . apply ( format ) ;
248
+ }
225
249
}
226
250
227
251
render ( ) {
228
- const { tagName : Tag = 'div' , style, className } = this . props ;
252
+ const { tagName : Tag = 'div' , style, focus , className } = this . props ;
229
253
const classes = classnames ( 'blocks-editable' , className ) ;
230
254
231
- return (
255
+ let element = (
232
256
< Tag
233
- ref = { this . bindNode }
257
+ ref = { this . bindEditorNode }
234
258
style = { style }
235
- className = { classes } />
259
+ className = { classes }
260
+ key = "editor" />
236
261
) ;
262
+
263
+ if ( focus ) {
264
+ element = [
265
+ < Fill name = "Formatting.Toolbar" key = "fill" >
266
+ < Toolbar
267
+ controls = { formattingControls . map ( ( control ) => ( {
268
+ ...control ,
269
+ onClick : ( ) => this . toggleFormat ( control . format ) ,
270
+ isActive : this . isFormatActive ( control . format )
271
+ } ) ) } />
272
+ </ Fill > ,
273
+ element
274
+ ] ;
275
+ }
276
+
277
+ return element ;
237
278
}
238
279
}
0 commit comments