mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-08-24 13:12:56 +08:00
148 lines
3.3 KiB
TypeScript
148 lines
3.3 KiB
TypeScript
import { FileRepository, Plugin, type FileLoader, type UploadAdapter } from "ckeditor5";
|
|
|
|
export default class UploadimagePlugin extends Plugin {
|
|
static get requires() {
|
|
return [ FileRepository ];
|
|
}
|
|
|
|
static get pluginName() {
|
|
return 'UploadimagePlugin';
|
|
}
|
|
|
|
init() {
|
|
this.editor.plugins.get('FileRepository').createUploadAdapter = loader => new Adapter(loader);
|
|
}
|
|
}
|
|
|
|
class Adapter implements UploadAdapter {
|
|
private loader: FileLoader;
|
|
private xhr?: XMLHttpRequest;
|
|
|
|
/**
|
|
* Creates a new adapter instance.
|
|
*/
|
|
constructor(loader: FileLoader) {
|
|
/**
|
|
* FileLoader instance to use during the upload.
|
|
*/
|
|
this.loader = loader;
|
|
}
|
|
|
|
/**
|
|
* Starts the upload process.
|
|
*
|
|
* @see module:upload/filerepository~Adapter#upload
|
|
*/
|
|
upload() {
|
|
return this.loader.file
|
|
.then( file => new Promise<File | null>( ( resolve, reject ) => {
|
|
this._initRequest().then(() => {
|
|
this._initListeners(resolve, reject);
|
|
this._sendRequest();
|
|
});
|
|
} ) ) as Promise<any>;
|
|
}
|
|
|
|
/**
|
|
* Aborts the upload process.
|
|
*
|
|
* @see module:upload/filerepository~Adapter#abort
|
|
* @returns {Promise}
|
|
*/
|
|
abort() {
|
|
if (this.xhr) {
|
|
this.xhr.abort();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initializes the XMLHttpRequest object.
|
|
*
|
|
* @private
|
|
*/
|
|
_initRequest() {
|
|
return glob.getHeaders().then(headers => {
|
|
const xhr = this.xhr = new XMLHttpRequest();
|
|
|
|
const {noteId} = glob.getActiveContextNote();
|
|
|
|
// this must be a relative path
|
|
const url = `api/notes/${noteId}/attachments/upload`;
|
|
|
|
xhr.open('POST', url, true);
|
|
xhr.responseType = 'json';
|
|
|
|
for (const headerName in headers) {
|
|
xhr.setRequestHeader(headerName, headers[headerName]);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initializes XMLHttpRequest listeners.
|
|
*
|
|
* @private
|
|
* @param resolve Callback function to be called when the request is successful.
|
|
* @param reject Callback function to be called when the request cannot be completed.
|
|
*/
|
|
async _initListeners(resolve: (value: File | PromiseLike<File | null> | null) => void, reject: (reason?: any) => void) {
|
|
const xhr = this.xhr;
|
|
if (!xhr) {
|
|
reject("Missing XHR");
|
|
return;
|
|
}
|
|
|
|
const loader = this.loader;
|
|
const file = await loader.file;
|
|
if (!file) {
|
|
reject("Missing file");
|
|
return;
|
|
}
|
|
|
|
const genericError = 'Cannot upload file:' + ` ${file.name}.`;
|
|
|
|
xhr.addEventListener('error', () => reject(genericError));
|
|
xhr.addEventListener('abort', () => reject());
|
|
xhr.addEventListener('load', () => {
|
|
const response = xhr.response;
|
|
|
|
if (!response || !response.uploaded) {
|
|
return reject(response && response.error && response.error.message ? response.error.message : genericError);
|
|
}
|
|
|
|
resolve({
|
|
default: response.url
|
|
} as unknown as File);
|
|
});
|
|
|
|
// Upload progress when it's supported.
|
|
/* istanbul ignore else */
|
|
if (xhr.upload) {
|
|
xhr.upload.addEventListener('progress', evt => {
|
|
if (evt.lengthComputable) {
|
|
loader.uploadTotal = evt.total;
|
|
loader.uploaded = evt.loaded;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prepares the data and sends the request.
|
|
*
|
|
* @private
|
|
*/
|
|
async _sendRequest() {
|
|
// Prepare form data.
|
|
const data = new FormData();
|
|
|
|
const file = await this.loader.file;
|
|
if (file) {
|
|
data.append('upload', file);
|
|
|
|
// Send request.
|
|
this.xhr?.send(data);
|
|
}
|
|
}
|
|
}
|