Writing in the front
Recently there was a project that needed an editor, and the boss said that he wanted to add some extensions with a simpler framework, rather than using a heavier one like Ckeditor. After comparison, the UEditor was not maintained and the others seemed not to meet my needs, so I chose Tinymce because tinymCE is lightweight and easy to expand, and is fully open source and can be used for commercial applications.
After a preliminary look at the document, I need to have a picture uploading plug-in, but the existing plug-in does not meet my requirements. What I need is to click or drag to dialog to open the picture directory immediately. The existing plug-in adopts tab-panel mode, with many unnecessary things like pasting URL. Looking at Github, it seems that someone else’s implementation doesn’t quite fit my needs either, hence the events described in the title.
To prepare
Download generator
npm install --global yo generator-tinymce
Copy the code
Create a plug-in template with the generator
The generated directory can be the corresponding directory of the source code or you can use the directory you want to use, fill in the name of the plug-in, and then next
yo tinymce
Copy the code
Once you have created the template, you will see the corresponding script
# Hot update project
yarn start
# build project
yarn build
Copy the code
The main development directory is under SRC /main, and plugin.ts is the main plugin entry where you can write plugin content
The realization of picture upload plug-in
Declare the plug-in
To write a plugin, declare it and add it to the editor, like this:
declare const tinymce: any;
const setup = (editor, url) = > {
editor.ui.registry.addButton('image-t', {
icon: 'image'.tooltip: 'image-t'.onAction: () = > {
// tslint:disable-next-line:no-console
editor.execCommand('mceInsertContent'.false.`<p>Hello world</p>`); }}); };export default () => {
tinymce.PluginManager.add('image-t', setup);
};
Copy the code
Copy the image-t to the tinymce/plugins directory to use the image-t plugin. For example, copy the image-t to the plugins directory. You’ll see an image tool in the toolbar, and clicking on it will insert ‘Hello World ‘into the editor.
tinymce.init({
selector: 'textarea.tinymce'.plugins: 'image-t'.toolbar: 'image-t'});Copy the code
2. Image uploading interface realization
In the last step, we have tried to experience the pleasure of writing plugins, but this is just the beginning, it seems that I can only insert some text, it is not useful, I want to insert pictures. Think about what we usually do when we want to insert an image?
First of all, there should be a UI that prompts you to upload an image. Clicking on a button will take you to a local directory, you can select an image, and clicking OK will insert the image.
The first step is to click on the button generated in the previous step and a box will pop up with some information. Before writing this demo, take a look at the source code of the existing image plugin.
The image plug-in uses the Dialog UI component, which is used to open a pop-up box. We first look at the relevant UI components, and find that there are two modes to choose from. The Image plug-in uses the TabPanel mode, which can have multiple tabs. There’s no need to use this, so go with Panel.
In addition to the first time, the Dialog also has to configure buttons, which is required, so I left it empty.
Armed with this knowledge, we can now write a popbox with an interface. We are extending the demo above
declare const tinymce: any;
const setup = (editor, url) = > {
editor.ui.registry.addButton('image-t', {
icon: 'image'.tooltip: 'image-t'.onAction: () = > {
// tslint:disable-next-line:no-console
const dialogConfig = {
title: 'Upload picture'.body: {
type: 'panel'.items: []},buttons: [],}; editor.windowManager.open(dialogConfig); }}); };export default () => {
tinymce.PluginManager.add('image-t', setup);
};
Copy the code
To preview the rest of the demo, click the image button and a blank box will pop up indicating that the first step of the modification was successful. Compile it again and put it under Tinymce /plugins.
3. Select an image and upload it
Normally, to open a local directory, we would think of input, but here we have to exclude this option first. Why? Because we are in the development of a plug-in ah, the source code must be exposed to the relevant interface.
Let’s go back to the image plugin. UploadTab has a layer of dialog configuration as follows
const makeTab = (_info: ImageDialogInfo) = > {
const items: Dialog.BodyComponentSpec[] = [
{
type: 'dropzone'.name: 'fileinput',},];return {
title: 'Upload'.name: 'upload',
items,
};
};
Copy the code
Dropzone = dropzone = dropzone = dropzone = dropzone = dropzone
declare const tinymce: any;
const setup = (editor, url) = > {
editor.ui.registry.addButton('image-t', {
icon: 'image'.tooltip: 'image-t'.onAction: () = > {
// tslint:disable-next-line:no-console
const dialogConfig = {
title: 'Upload picture'.body: {
type: 'panel'.items: [{type: 'dropzone'.name: 'fileinput',}]},buttons: [],}; editor.windowManager.open(dialogConfig); }}); };export default () => {
tinymce.PluginManager.add('image-t', setup);
};
Copy the code
Repeat the steps above, and the dialog now has a few more prompts and a browse image button that opens the local directory and selects images.
Is that all right? Our goal is to insert an image into the edit box, so we have to upload the image first, and uploading the image requires taking the image.
In the previous Dialog document we saw some configuration items, including an onChange method that is triggered when the input value is changed. The method first parameter is dialogApi, which contains some input value related meta information, analysis will know that this is the data we want. However, uploading takes a period of time. Here, we select an image and load it, and then upload it. After uploading, we insert the image into the editor, cancel loading, close the popover, and write a simple demo
declare const tinymce: any;
const setup = (editor, url) = > {
editor.ui.registry.addButton('image-t', {
icon: 'image'.tooltip: 'image-t'.onAction: () = > {
// tslint:disable-next-line:no-console
const dialogConfig = {
title: 'Upload picture'.body: {
type: 'panel'.items: [{type: 'dropzone'.name: 'fileinput',}]},buttons: [].onChange(api) {
api.block('On... '); uploadImg(api, editor); }}; editor.windowManager.open(dialogConfig); }}); };export default () => {
tinymce.PluginManager.add('image-t', setup);
};
Copy the code
In the demo above, loading was implemented after the image was opened and uploadImg function was added to realize the uploading logic. So far, the plug-in has gradually formed, but it seems that the code is a little bloated, let’s split it
const dialog = (editor) = > {
return {
title: 'Upload picture'.body: {
type: 'panel'.items: [{type: 'dropzone'.name: 'fileinput'.label: ' ',}]},buttons: [].onChange(api) {
api.block('On... '); uploadImg(api, editor); }}; };const setup = (editor, url) = > {
editor.ui.registry.addButton('image-t', {
icon: 'image'.tooltip: 'image-t'.onAction: () = > {
// tslint:disable-next-line:no-console
constdialogConfig = dialog(editor); editor.windowManager.open(dialogConfig); }}); };export default () => {
tinymce.PluginManager.add('image-t', setup);
};
Copy the code
It’s much more comfortable to break it down, so go on.
Upload pictures to Qiniu
To upload a resource, you first have to think of using a network request. I thought of Axios because it was compact and compatible, but realized that AXIos was wrapped in CJS and had some problems compiling, so I ended up using XHR to reduce dependencies. Image upload seven cows need to have image meta information, can be obtained through api.getData, in addition to the need for file type, can also be obtained through this method, implementation can be so
function getUrl(formdata, callback) {
const xhr = new XMLHttpRequest();
xhr.open("POST", <url>, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
callback(JSON.parse(xhr.response)); }}; xhr.send(formdata); }Copy the code
Through the above method we can get the url uploaded to the seven cows picture, of course, this is only a demo, specific can be achieved according to their own situation
Insert the image into the editor
So we finally got our image URL, so we can happily insert it into our editor, and combined with the previous step, our final uploadImage function could be written like this
function uploadImg(api, editor) {
const data = api.getData();
const image = data.fileinput[0];
const fileExt = image.name.split('. ') [1];
const getToken = (resp) = > {
const token = resp.F_token;
const formdata = new FormData();
formdata.append('file', image);
formdata.append('token', token);
getUrl(formdata, (res) = > {
const img = res.url;
api.setData({ src: { value: res.url, meta: {}}}); editor.execCommand('mceInsertContent'.false.`<img src=${img} class="img-t" alt='img-t'/>`
);
api.unblock();
api.close();
});
};
getQiniuToken(fileExt, getToken);
}
Copy the code
I spent a day and a half studying this, taking notes, and plug-in development is that simple
References:
HTML rich text compiler UEditor, CKEditor, TinyMCE, HTMLArea, eWebEditor, KindEditor
TinyMCE plugin Yeoman generator
Create a plugin for TinyMCE