// Copyright (C) 2023 Vaughn Nugent // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import { ComputedContent } from "@vnuge/cmnext-admin"; import { IToaster } from "@vnuge/vnlib.browser"; import { isNil } from "lodash-es"; import type { AxiosRequestConfig } from "axios"; import type { Editor } from "@ckeditor/ckeditor5-core"; import type { UploadAdapter, UploadResponse, FileLoader } from '@ckeditor/ckeditor5-upload' export type ApiCall = (callback: (data: any) => Promise) => Promise; export type CKEditorPlugin = (editor: Editor) => void; /** * Creates a CKEditor plugin that adds an upload adapter to the editor * @param content The content api instance * @param apiCall A callback function that wraps the api call * @returns A CKEditor plugin initializer */ export const useUploadAdapter = (content: ComputedContent, apiCall: ApiCall, toaster?: IToaster): CKEditorPlugin =>{ const createUploadAdapter = (loader: FileLoader): UploadAdapter => { const abortController = new AbortController(); /** * Init request config local to a */ const requestConfig = { signal: abortController.signal, onUploadProgress: (progressEvent: ProgressEvent) => { loader.uploadTotal = progressEvent.total; loader.uploaded = Math.round(progressEvent.loaded * 100); } } as unknown as AxiosRequestConfig; const upload = async (): Promise => { //Get the file const file = await loader.file; if(isNil(file)){ return{ default: '' } } //Exec server operations const url = await apiCall(async () => { //Upload the file const meta = await content.uploadContent(file, file.name, requestConfig); toaster?.info({ title: 'Upload Complete', text: `Successfully uploaded file ${file.name} ID:${meta.id}` }) //Get the public url return await content.getPublicUrl(meta); }) as string //Reload content content.refresh(); //Default url as the returned file url return { default: url } } const abort = () => { abortController.abort('Upload aborted'); } return { upload, abort } } return function (editor: Editor): void { //Add the upload adapter factory to the editor editor.plugins.get('FileRepository').createUploadAdapter = createUploadAdapter; }; }