npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@itshixun/qckeditor-plugin-file

v1.0.1

Published

CKEditor 5 plugin for file upload

Downloads

279

Readme

@itshixun/qckeditor-plugin-file

CKEditor 5 插件:通用文件上传。在编辑器中插入可下载的文件链接,支持本地上传和直接插入已有文件,支持多文件上传和自动文件类型识别。

安装

npm install @itshixun/qckeditor-plugin-file
# 或
pnpm add @itshixun/qckeditor-plugin-file

依赖 ckeditor5(peerDependencies,需自行安装)。

基本使用

1. 引入样式

import '@itshixun/qckeditor-plugin-file/dist/index.css';

2. 注册插件

import { ClassicEditor } from 'ckeditor5';
import { QstFile } from '@itshixun/qckeditor-plugin-file';

const editor = await ClassicEditor.create(element, {
  plugins: [
    // ... 其他插件
    QstFile,
  ],
  toolbar: [
    // ... 其他按钮
    'uploadFile',  // 工具栏按钮名称:上传文件
  ],
  qstFile: {
    upload: {
      types: ['txt', 'rar', 'zip', 'doc', 'docx', 'pdf', 'xls', 'xlsx'],
      maxSize: 100 * 1024 * 1024, // 100MB
    },
    progress: {
      showProgressBar: true,
      useReadOnlyLock: false,
    },
  },
});

3. Vue 中使用

<script setup lang="ts">
import { ClassicEditor } from 'ckeditor5';
import { QstFile } from '@itshixun/qckeditor-plugin-file';

const config = {
  editor: ClassicEditor,
  plugins: [/* ... */, QstFile],
  toolbar: ['bold', 'italic', 'uploadFile'],
  qstFile: {
    upload: {
      types: ['pdf', 'docx', 'xlsx'],
      maxSize: 50 * 1024 * 1024,
    },
  },
};
</script>

<template>
  <ckeditor :editor="config.editor" :config="config" />
</template>

配置项

| 属性 | 类型 | 必填 | 说明 | |------|------|------|------| | upload.types | string[] | 否 | 允许上传的文件扩展名列表,默认 ['txt', 'rar', 'zip', 'doc', 'docx', 'pdf', 'xls', 'xlsx'] | | upload.maxSize | number | 否 | 最大文件大小(字节),超出会提示警告 | | progress.showProgressBar | boolean | 否 | 是否显示上传进度条,默认 true | | progress.useReadOnlyLock | boolean | 否 | 上传期间是否锁定编辑器为只读模式,默认 false |

上传配置

本插件依赖 CKEditor 5 的 FileRepository 插件处理文件上传。你需要配置一个自定义的 UploadAdapter,否则上传功能无法正常工作。

自定义 UploadAdapter 实现示例

import type { FileLoader, UploadAdapter } from 'ckeditor5';

class MyUploadAdapter implements UploadAdapter {
  private loader: FileLoader;
  private xhr?: XMLHttpRequest;

  constructor(loader: FileLoader) {
    this.loader = loader;
  }

  upload(): Promise<{ default: string }> {
    return this.loader.file.then(
      (file) =>
        new Promise((resolve, reject) => {
          this._initRequest();
          this._initListeners(resolve, reject, file!);
          this._sendRequest(file!);
        })
    );
  }

  abort(): void {
    if (this.xhr) {
      this.xhr.abort();
    }
  }

  private _initRequest(): void {
    const xhr = (this.xhr = new XMLHttpRequest());
    xhr.open('POST', 'https://your-api.com/upload', true);
    xhr.responseType = 'json';
  }

  private _initListeners(
    resolve: (value: { default: string }) => void,
    reject: (reason?: string) => void,
    file: File
  ): void {
    const xhr = this.xhr!;
    const loader = this.loader;
    const genericErrorText = `无法上传文件: ${file.name}.`;

    xhr.addEventListener('error', () => reject(genericErrorText));
    xhr.addEventListener('abort', () => reject());
    xhr.addEventListener('load', () => {
      const response = xhr.response;

      if (!response || response.error) {
        return reject(response?.error?.message || genericErrorText);
      }

      // 响应必须包含 default 字段(文件 URL)
      resolve({ default: response.url });
    });

    if (xhr.upload) {
      xhr.upload.addEventListener('progress', (evt) => {
        if (evt.lengthComputable) {
          loader.uploadTotal = evt.total;
          loader.uploaded = evt.loaded;
        }
      });
    }
  }

  private _sendRequest(file: File): void {
    const data = new FormData();
    data.append('file', file);
    this.xhr!.send(data);
  }
}

在编辑器中注册 UploadAdapter

function MyUploadAdapterPlugin(editor: any) {
  editor.plugins.get('FileRepository').createUploadAdapter = (loader: FileLoader) => {
    return new MyUploadAdapter(loader);
  };
}

const editor = await ClassicEditor.create(element, {
  plugins: [
    // ... 其他插件
    MyUploadAdapterPlugin, // 必须先注册,再注册 QstFile
    QstFile,
  ],
  toolbar: ['uploadFile'],
});

重要:

  • MyUploadAdapterPlugin 必须在 QstFile 之前注册到 plugins 数组中
  • 上传响应必须返回 { default: '文件URL' } 格式,default 字段会被提取为文件的 url
  • 上传失败时会自动移除占位文件元素,并通过 Notification 插件显示警告

命令说明

插件注册了两个命令,分别对应不同的使用场景:

fileInsert — 插入已有文件

通过文件 URL 直接插入已有文件(不上传):

editor.execute('fileInsert', {
  name: '示例文档.pdf',
  url: 'https://example.com/files/doc.pdf',
  filetype: 'pdf', // 可选,默认 'document'
});

uploadFile — 上传本地文件

通常由工具栏按钮自动触发,也可手动调用。支持多文件上传:

const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
const files = Array.from(fileInput.files!);

editor.execute('uploadFile', { file: files });

输出 HTML

保存态(Data Downcast)

<a class="ck-file ck-qst-file ck-qst-file-pdf"
   href="https://example.com/files/doc.pdf"
   download="download"
   data-filetype="pdf">
   示例文档.pdf
</a>

编辑态(Editing Downcast)

编辑态会渲染为 CKEditor 5 的 Widget,带有选中高亮和进度条:

<a class="ck-file ck-qst-file ck-qst-file-pdf ck-widget"
   href="https://example.com/files/doc.pdf"
   download="download"
   data-filetype="pdf"
   contenteditable="false">
   示例文档.pdf
   <!-- 上传时显示进度条 -->
   <div class="ck-qst-file-progress-bar" style="width: 45%"></div>
</a>

文件类型 class

插件根据 filetype 属性在 class 中添加类型标识,方便自定义不同文件类型的样式:

| 文件类型 | class 后缀 | |----------|-----------| | pdf | ck-qst-file-pdf | | doc / docx | ck-qst-file-doc | | xls / xlsx | ck-qst-file-xls | | ppt | ck-qst-file-ppt | | rar / zip | ck-qst-file-rar | | img | ck-qst-file-img | | video | ck-qst-file-video | | 其他 | ck-qst-file-document |

数据兼容性

插件在 upcast(粘贴/加载 HTML)时兼容旧版格式:

| 新版本 | 旧版本 | |--------|--------| | <a class="ck-qst-file"> | <a class="ck-file"> |

旧版 HTML 会被自动转换为新版数据模型,保存时输出新版格式(同时保留 ck-file 类以兼容旧样式):

<!-- 旧版输入 -->
<a class="ck-file" href="..." download data-filetype="pdf">文档.pdf</a>

<!-- 新版输出 -->
<a class="ck-file ck-qst-file ck-qst-file-pdf" href="..." download data-filetype="pdf">文档.pdf</a>

类型支持

导入插件后,EditorConfig 类型自动扩展,TypeScript 可直接识别 qstFile 配置:

const config: EditorConfig = {
  // 无类型错误,qstFile 已声明
  qstFile: {
    upload: { types: ['pdf'], maxSize: 1024 * 1024 },
  },
};

导出 API

import {
  QstFile,              // 主插件(Editing + Upload)
  QstFileEditing,       // 编辑插件(Schema + Conversion + fileInsert 命令)
  QstFileCommand,       // 插入已有文件的命令
  QstFileUpload,        // 上传功能聚合插件
  QstFileUploadEditing, // 上传编辑插件(自动上传处理 + 进度管理)
  QstFileUploadUI,      // 上传 UI 插件(工具栏按钮)
  QstFileUploadProgress, // 上传进度条插件
  QstFileUploadCommand, // 上传文件的命令
  insertFile,           // 工具函数:插入文件元素
  isFileAllowed,        // 工具函数:检查是否允许插入文件
  getFileType,          // 工具函数:根据 File 对象识别文件类型
  type QstFileConfig,
  type FileInsertCommandOptions,
  type UploadFileCommandOptions,
} from '@itshixun/qckeditor-plugin-file';