codeslayer1 / react-ckeditor

CKEditor component for React with plugin and custom event listeners support
MIT License
130 stars 34 forks source link

Paste inline images #45

Closed RaulEscobarRivas closed 6 years ago

RaulEscobarRivas commented 6 years ago

Hello,

First of all I'd like to thank you for putting this together, I've been trying to integrate CKEditor 4 & 5 within a react components library and I know how painful it is to integrate with a vDom, specially when not using a index.html file, so this is really helpful.

Now to the problem at hand:

I'm trying to set up the inline image pasting feature of CKEditor 4, I realize you use version 4.6 so it shouldn't be a problem.

However, I'm encountering two blockers, that I'm sure you already thought/faced them before:

  1. As pointed in https://docs.ckeditor.com/ckeditor4/latest/guide/dev_file_upload.html#basic-configuration, I'd like to set some parameters to configure the file upload plugin, like the upload URL. But when trying to pass these parameters as a config prop to your component, I'm getting this error (sorry for no screenshots, I'm behind a proxy right now so cant upload):

Error: [CKEDITOR.resourceManager.load] Resource name "uploadimage" was not found at "https://cdn.ckeditor.com/4.6.2/standard/plugins/uploadimage/plugin.js?t=H0CG".

My configuration object:

{ extraPlugins: 'uploadimage' }

  1. I'd like to subscribe to the fileUploadRequest event of the editor, as shown in https://docs.ckeditor.com/ckeditor4/latest/guide/dev_file_upload.html#request-2, so the first problem I encountered is that I'm not sure how to get the instance of my CKEditor? so I thought of getting it from one of the events defined in your events prop, I wrote this:

onEditorAfterPaste = event => { event.editor.on('fileUploadRequest', evt => { console.log('file fileUploadRequest fired, ', evt); }); };

Hoping it would fire when trying to paste an image in. Of course it didn't fire the console.log. I'm passing this onEditorAfterPaste callback on the events prop as the afterPaste value, and I already made sure that when pasting it triggers the callback, but the subscription isn't happening, so maybe getting the instance of the editor through one of the events method is not the right thing to do it?

Thanks in advance for reading this and keep slaying!

codeslayer1 commented 6 years ago

Hi, Glad that you found the package helpful.

Can you please share your source code? This will help me debug the issue you are facing with the integration.

RaulEscobarRivas commented 6 years ago

Hi, thank you for answering,

This is the code:

`class ComposeMessage extends Component { state = { subject: getInitialSubject(this.props.subject, this.props.type), content: 'Im the Rich text editor !' };

fromOnChangeHandler = value => this.props.fromOnChangeCallback && this.props.fromOnChangeCallback(value);

handleSubjectChange = event => this.setState({ subject: event.target.value });

onEditorChange = event => this.setState({ content: event.editor.getData() });

onEditorAfterPaste = event => { event.editor.on('fileUploadRequest', evt => { console.log('file fileUploadRequest fired, ', evt); }); };

render() { const { className, classes, from, to, negativeActionOptions, positiveActionOptions } = this.props; const { subject } = this.state;

return (
  <ThemeProvider theme={createToolkitTheme('light')}>
    <div className={classNames(className, classes.root)}>
      <div className={classes.header}>{subject}</div>
      <div className={classes.body}>
        <div className={classes.from}>
          <span>From</span>
          <FromField items={from} onChange={this.fromOnChangeHandler} />
        </div>
        <div className={classes.to}>
          <MultipleAutocomplete
            helperText="Enter Business Group, Client Contact, Employee Name or Email"
            suggestions={to}
          />
        </div>
        <div className={classes.subject}>
          <TextField
            label="Subject"
            onChange={this.handleSubjectChange}
            value={getSubject(subject)}
          />
        </div>
        <div className={classes.textEditor}>
          <CKEditor
            config={{
              extraPlugins: 'uploadimage'
            }}
            content={this.state.content}
            events={{
              "afterPaste": this.onEditorAfterPaste,
              "change": this.onEditorChange
            }}
         />
        </div>
      </div>
      <div className={classes.footer}>
        <Button onClick={positiveActionOptions.callback} type="cta">
          {positiveActionOptions.label}
        </Button>
        <Button onClick={negativeActionOptions.callback} type="secondary">
          {negativeActionOptions.label}
        </Button>
      </div>
    </div>
  </ThemeProvider>
);

} }`

codeslayer1 commented 6 years ago

Hi,

Please find my response to both your issues.

  1. To enable image upload plugin, you first need to have it in your build. Only then you can enable it via config. The standard 4.6.2 version does not include imageupload (not very sure), hence the error. The same code works using the latest standard version 4.9.2. You just need to make a minor change in config which is adding the upload url (Refer this)
config={{
          extraPlugins: 'uploadimage',
          uploadUrl: '/uploader/upload.php'
        }}

In case you still need to use the 4.6.2 version, you can either use the full build or create your custom build and use it by following the steps here. #7

  1. Your code is working fine for me. You must not be getting event fired because in your case the image upload plugin must not be working (it doesn't work without a upload url). So try the above fix and recheck. You should get the event. A minor suggestion though, instead of listening for the afterPaste event and then again listening for fileUploadRequest event inside it, you can directly listen to fileUploadRequest event like this.
fileUploadRequest = event => {
    console.log("fileUploadRequest, ", event);
};

<CKEditor
    config={{
      extraPlugins: 'uploadimage',
      uploadUrl: '/uploader/upload.php'
    }}
    content={this.state.content}
    events={{
      "fileUploadRequest": this.fileUploadRequest,
      "change": this.onEditorChange
    }}
/>

Please let me know in case you still face any issue.

codeslayer1 commented 6 years ago

@RaulEscobarRivas Hey. Was your issue resolved using the above fix? Please let me know so that I can close the issue.

RaulEscobarRivas commented 6 years ago

@codeslayer1 Hello,

Yes, your code examples work perfectly, thank you!

I'm just having a different kind of issue, it looks like I won't be able to merge this into our code as blackduck scanner will raise a warning as we are not allowed to have code that includes resources from an external URL (the part that loadScript is doing).

So I'm thinking of somehow (maybe using webpack) have ckeditor as global variable in my package and edit your code to not go and get the CDN ckeditor.

If you have any suggestion I'd be more than happy to check it, other than that you can close this issue :)

codeslayer1 commented 6 years ago

I am not sure if it would be possible for you but you download the CKEditor bundle and place it in your company's server location somewhere where you can access it and then point the script url to your company's server.

I will keep the issue open for 2-3 days. In case you are struck somewhere, do let me know :)

RaulEscobarRivas commented 6 years ago

Thank you!

you da real mvp :)

codeslayer1 commented 6 years ago

Closing this issue due to no further activity.