hello my fellow developers 🙌
One of the main issues when dealing with WYSIWYG editors is uploading media (audio, video, image, etc.)
there are always limitations on how to upload certain media and of course developers have come up with professional solutions that might help you in managing your files (tools like CKBox), but what if you just want to use your personal custom editor for a change?
Step 1: Create a Nextjs project
to begin, open the terminal and run the following command:
npx create-next-app
you can also activate Typescript, ESlint and other options if you intend to use them in your project.
Step 2: Create a custom build
you can choose your own ckeditor5 toolbar and plugins by going to CKEditor Online Builder and download the package.
unzip it and then copy the folder into your project's src folder and change these lines in ckeditor5/build/ckeditor.js
acceptedType:r.map((t=>`image/${t}`)).join(","))
to:
acceptedType:'*'
i=Array.from(n).filter((t=>s.test(t.type)))
to
i=Array.from(n)
and finally run npm install file:src/ckeditor5
you should now see ckeditor5-custom-build
in your package.json
you should also install ckeditor package for react
npm install @ckeditor/ckeditor5-react"
step 3: Add editor to page
make a new folder inside app directory and rename it to blog.
then create a page.tsx
and CustomEditor
component:
// CustomEditor.js
import { CKEditor } from '@ckeditor/ckeditor5-react'
import Editor from 'ckeditor5-custom-build'
import axios from 'axios'
// upload Adaptor
function uploadAdapter(loader) {
return {
upload: () => {
return new Promise((resolve, reject) => {
const fd = new FormData()
loader.file.then((file) => {
// here check the mimetype and send request
// to relevant backend api endpoint
axios
.post(`https://sample.com/files/${endPoint}`, fd)
.then((res) => {
resolve({
default: res.data[0].fileAddress
})
})
.catch((err) => {
reject(err)
})
})
})
},
}
}
function uploadPlugin(editor) {
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
return uploadAdapter(loader)
}
// when upload completes, replace tag
const imageUploadEditing = editor.plugins.get('ImageUploadEditing')
imageUploadEditing.on('uploadComplete', (evt, { data, imageElement }) => {
editor.model.change((writer) => {
const view = editor.data.processor.toView(
data.mediaType === 'video'
? `<video src='${data.default}' controls="controls"></video>`
: data.mediaType === 'audio'
? `<audio src='${data.default}' controls="controls"></audio>`
: `<img src='${data.default}' />`
)
const model = editor.data.toModel(view)
editor.model.insertContent(model, editor.model.document.selection)
})
evt.stop()
editor.editing.view.focus()
})
}
const editorConfiguration = {
placeholder: 'write your content...',
extraPlugins: [uploadPlugin],
toolbar: {
items: [
'heading',
'|',
'uploadImage',
'|',
'code',
'codeBlock',
'showBlocks',
'sourceEditing',
'|',
'undo',
'redo',
],
shouldNotGroupWhenFull: true,
},
simpleUpload: {
uploadUrl: `https://sample.com/files/editor`,
fileTypes: ['.pdf', '.doc', '.docx', '.xls', '.xlsx'],
},
image: {
upload: { types: ['mp4', 'pdf', 'mpeg', 'jpg', 'png'] },
},
htmlSupport: {
allow: [
{
name: /.*/,
attributes: true,
classes: true,
styles: true,
},
],
},
}
function CustomEditor(props) {
return (
<CKEditor
editor={Editor}
rows={7}
data={props?.content}
config={editorConfiguration}
onChange={(event, editor) => {
const newData = editor.getData()
props.handleContent(newData)
}}
/>
)
}
export default CustomEditor
// blog/page.tsx
'use client';
import dynamic from 'next/dynamic.js';
import { useState } from 'react';
const CustomEditor = dynamic(
() => {
return import('./CustomEditor.jsx');
},
{ssr: false}
);
const Blog = () => {
const [content, setContent] = useState("");
return (
<div>
<CustomEditor id="content" content={content} handleContent={(newContent: any) => setContent(newContent)} />
</div>
);
};
export default Blog;
you can use your custom endpoints to send data to your backend and receive the file address. basically the code tries to replace the tag in the editor using conversion
also don't forget you need to add your backend uploader for this code to work (I'm using multer and express in my own project).
Here's the result:
Top comments (2)
tnx, it was very useful and I needed this experience.