-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathtinymce.js
122 lines (103 loc) · 3.21 KB
/
tinymce.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
119
120
121
122
/**
* External dependencies
*/
import tinymce from 'tinymce';
import { isEqual } from 'lodash';
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { Component, Children, createElement } from '@wordpress/element';
/**
* Internal dependencies
*/
import { diffAriaProps, pickAriaProps } from './aria';
export default class TinyMCE extends Component {
componentDidMount() {
this.initialize();
}
shouldComponentUpdate() {
// We must prevent rerenders because TinyMCE will modify the DOM, thus
// breaking React's ability to reconcile changes.
//
// See: https://github.com/facebook/react/issues/6802
return false;
}
componentWillReceiveProps( nextProps ) {
const name = 'data-is-placeholder-visible';
const isPlaceholderVisible = String( !! nextProps.isPlaceholderVisible );
if ( this.editorNode.getAttribute( name ) !== isPlaceholderVisible ) {
this.editorNode.setAttribute( name, isPlaceholderVisible );
}
if ( ! isEqual( this.props.style, nextProps.style ) ) {
this.editorNode.setAttribute( 'style', '' );
Object.assign( this.editorNode.style, nextProps.style );
}
if ( ! isEqual( this.props.className, nextProps.className ) ) {
this.editorNode.className = classnames( nextProps.className, 'blocks-editable__tinymce' );
}
const { removedKeys, updatedKeys } = diffAriaProps( this.props, nextProps );
removedKeys.forEach( ( key ) =>
this.editorNode.removeAttribute( key ) );
updatedKeys.forEach( ( key ) =>
this.editorNode.setAttribute( key, nextProps[ key ] ) );
}
componentWillUnmount() {
if ( ! this.editor ) {
return;
}
// This hack prevents TinyMCE from trying to remove the container node
// while cleaning for destroy, since removal is handled by React. It
// does so by substituting the container to be removed.
this.editor.container = document.createDocumentFragment();
this.editor.destroy();
delete this.editor;
}
initialize() {
const { focus } = this.props;
const settings = this.props.getSettings( {
theme: false,
inline: true,
toolbar: false,
browser_spellcheck: true,
entity_encoding: 'raw',
convert_urls: false,
inline_boundaries_selector: 'a[href],code,b,i,strong,em,del,ins,sup,sub',
plugins: [],
formats: {
strikethrough: { inline: 'del' },
},
} );
settings.plugins.push( 'paste' );
tinymce.init( {
...settings,
target: this.editorNode,
setup: ( editor ) => {
this.editor = editor;
this.props.onSetup( editor );
},
} );
if ( focus ) {
this.editorNode.focus();
}
}
render() {
const { tagName = 'div', style, defaultValue, className } = this.props;
const ariaProps = pickAriaProps( this.props );
// If a default value is provided, render it into the DOM even before
// TinyMCE finishes initializing. This avoids a short delay by allowing
// us to show and focus the content before it's truly ready to edit.
let children;
if ( defaultValue ) {
children = Children.toArray( defaultValue );
}
return createElement( tagName, {
ref: ( node ) => this.editorNode = node,
contentEditable: true,
suppressContentEditableWarning: true,
className: classnames( className, 'blocks-editable__tinymce' ),
style,
...ariaProps,
}, children );
}
}