Skip to content

using file_picker_callback causes editor to reload with every change event that is fired #62

Description

I am using admin-on-rest and react-tinymce. When I include file_picker_callback in the tinymce config the editor will reload every time the onchange event fires.

This is an issue because users are not able to continually type (editor loses focus after reloading). I have tried manually setting the focus after it reloads, but it does not focus back to the same place the cursor was previously - so this is not a viable workaround.

If I remove the file_picker_callback, then everything works as expected.

Here is my code:

import React, { PropTypes, Component } from 'react'
import TinyMCE from 'react-tinymce'
import debounce from 'lodash.debounce';

class Editor extends Component {
    self;

    componentDidMount() {
        const {
            id,
            disabled,
            label,
            name,
            input: {
                value,
                onChange
            },
            config
        } = this.props;

        self = this;
    }

    onEditorChange = (content = window.tinyMCE.activeEditor.getContent()) => {
        if (self.props.input.value == content)
            return;

        self.props.input.onChange(content);
    }

    render() {
        return (
            <div>
                <input type="file" id="image-upload-tinymce" name="single-image" style={{ display: "none" }} accept="image/png, image/gif, image/jpeg, image/jpg, image/svg" />

                <TinyMCE
                    content={this.props.input.value}
                    config={{
                        plugins: [
                            'advlist autolink lists link image charmap print preview anchor',
                            'searchreplace wordcount visualblocks code',
                            'insertdatetime table contextmenu paste code'
                        ],
                        toolbar: 'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | code',
                        file_browser_callback_types: 'image',
                        file_picker_callback: (callback, value, meta) => {
                            if (meta.filetype == 'image') {

                                var input = document.getElementById('image-upload-tinymce');
                                input.click();

                                input.onchange = () => {
                                    var file = input.files[0];
                                    var reader = new FileReader();

                                    reader.onload = (e) => {
                                        var img = new Image();
                                        img.src = reader.result;

                                        callback(e.target.result, {
                                            alt: file.name
                                        });

                                        var delay = debounce(self.onEditorChange, 10000);

                                        delay();
                                    };

                                    reader.readAsDataURL(file);
                                };
                            }
                        },
                    }}
                    id={this.props.id}
                    onKeyup={e => {
                        e.stopPropagation();
                        e.preventDefault();

                        var delay = debounce(self.onEditorChange, 500);

                        delay();
                    }}

                />
            </div>
        )
    }

}

I have the following in my index.html:
<script src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.5.6/tinymce.min.js"></script>

What I have noticed is that during an onchange event there is a get request issued for:

https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.5.6/skins/lightgray/content.min.css

and the call stack for this request is as follows:


initContentBody	@	tinymce.min.js:11
init	@	tinymce.min.js:11
(anonymous)	@	tinymce.min.js:11
(anonymous)	@	tinymce.min.js:4
n	@	tinymce.min.js:3
v	@	tinymce.min.js:4
loadScripts	@	tinymce.min.js:4
loadQueue	@	tinymce.min.js:4
t	@	tinymce.min.js:11
render	@	tinymce.min.js:11
a	@	tinymce.min.js:12
(anonymous)	@	tinymce.min.js:12
n	@	tinymce.min.js:3
d	@	tinymce.min.js:12
t.bind	@	tinymce.min.js:2
bind	@	tinymce.min.js:4
init	@	tinymce.min.js:12
_init	@	TinyMCE.js:128
TinyMCE_componentWillReceiveProps	@	TinyMCE.js:66
(anonymous)	@	ReactCompositeComponent.js:611
measureLifeCyclePerf	@	ReactCompositeComponent.js:75
updateComponent	@	ReactCompositeComponent.js:610
receiveComponent	@	ReactCompositeComponent.js:547
receiveComponent	@	ReactReconciler.js:125
updateChildren	@	ReactChildReconciler.js:109
_reconcilerUpdateChildren	@	ReactMultiChild.js:208
_updateChildren	@	ReactMultiChild.js:312
updateChildren	@	ReactMultiChild.js:299
_updateDOMChildren	@	ReactDOMComponent.js:936
updateComponent	@	ReactDOMComponent.js:754
receiveComponent	@	ReactDOMComponent.js:716
receiveComponent	@	ReactReconciler.js:125
_updateRenderedComponent	@	ReactCompositeComponent.js:754
_performComponentUpdate	@	ReactCompositeComponent.js:724
updateComponent	@	ReactCompositeComponent.js:645
receiveComponent	@	ReactCompositeComponent.js:547
receiveComponent	@	ReactReconciler.js:125
updateChildren	@	ReactChildReconciler.js:109
_reconcilerUpdateChildren	@	ReactMultiChild.js:208
_updateChildren	@	ReactMultiChild.js:312
updateChildren	@	ReactMultiChild.js:299
_updateDOMChildren	@	ReactDOMComponent.js:936
updateComponent	@	ReactDOMComponent.js:754
receiveComponent	@	ReactDOMComponent.js:716
receiveComponent	@	ReactReconciler.js:125
_updateRenderedComponent	@	ReactCompositeComponent.js:754
_performComponentUpdate	@	ReactCompositeComponent.js:724
updateComponent	@	ReactCompositeComponent.js:645
receiveComponent	@	ReactCompositeComponent.js:547
receiveComponent	@	ReactReconciler.js:125
_updateRenderedComponent	@	ReactCompositeComponent.js:754
_performComponentUpdate	@	ReactCompositeComponent.js:724
updateComponent	@	ReactCompositeComponent.js:645
receiveComponent	@	ReactCompositeComponent.js:547
receiveComponent	@	ReactReconciler.js:125
_updateRenderedComponent	@	ReactCompositeComponent.js:754
_performComponentUpdate	@	ReactCompositeComponent.js:724
updateComponent	@	ReactCompositeComponent.js:645
receiveComponent	@	ReactCompositeComponent.js:547
receiveComponent	@	ReactReconciler.js:125
_updateRenderedComponent	@	ReactCompositeComponent.js:754
_performComponentUpdate	@	ReactCompositeComponent.js:724
updateComponent	@	ReactCompositeComponent.js:645
performUpdateIfNecessary	@	ReactCompositeComponent.js:561
performUpdateIfNecessary	@	ReactReconciler.js:157
runBatchedUpdates	@	ReactUpdates.js:150
perform	@	Transaction.js:140
perform	@	Transaction.js:140
perform	@	ReactUpdates.js:89
flushBatchedUpdates	@	ReactUpdates.js:172
closeAll	@	Transaction.js:206
perform	@	Transaction.js:153
batchedUpdates	@	ReactDefaultBatchingStrategy.js:62
enqueueUpdate	@	ReactUpdates.js:200
enqueueUpdate	@	ReactUpdateQueue.js:24
enqueueSetState	@	ReactUpdateQueue.js:219
ReactComponent.setState	@	ReactComponent.js:63
handleChange	@	connect.js:302
dispatch	@	createStore.js:186
(anonymous)	@	middleware.js:22
(anonymous)	@	middleware.js:80
boundChange	@	createFieldProps.js:97
(anonymous)	@	createOnChange.js:37
Editor._this.onEditorChange	@	editor.js:29
invokeFunc	@	index.js:160
trailingEdge	@	index.js:207
timerExpired	@	index.js:195

From the call stack, line 66 of TinyMCE.js is:

componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
    if (!(0, _lodashLangIsEqual2['default'])(this.props.config, nextProps.config)) {
      this._init(nextProps.config, nextProps.content);//line 66 here
    }

line 128 is tinymce.init(config);

I believe this is a bug with react-tinymce (and not admin-on-rest) - but I am not very familiar with react, so I could be wrong.

Any help or insight would be appreciated. I have spent 2 days debugging this and have made no progress

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions