CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-wangeditor

Lightweight web-based rich text editor (WYSIWYG editor) built with JavaScript and CSS for modern browsers

Pending
Overview
Eval results
Files

image-upload.mddocs/

Image Upload

Image upload functionality with support for local uploads, network images, and various cloud storage services.

Capabilities

Upload Images

Upload image files to the editor.

/**
 * Upload image files to the editor
 * @param files - FileList or Array of File objects to upload
 */
uploadImg(files: FileList | File[]): void;

Usage Examples:

// Upload from file input
const fileInput = document.getElementById('imageInput');
fileInput.addEventListener('change', function(e) {
    if (e.target.files.length > 0) {
        editor.uploadImg.uploadImg(e.target.files);
    }
});

// Upload programmatically
function uploadImages(files) {
    editor.uploadImg.uploadImg(files);
}

// Drag and drop upload
const dropZone = document.getElementById('editor-container');
dropZone.addEventListener('drop', function(e) {
    e.preventDefault();
    const files = Array.from(e.dataTransfer.files).filter(file => 
        file.type.startsWith('image/')
    );
    if (files.length > 0) {
        editor.uploadImg.uploadImg(files);
    }
});

Upload Configuration

Server Configuration

Configure server endpoint and upload parameters.

interface ServerConfig {
  /** Server endpoint for image upload */
  uploadImgServer?: string;
  
  /** Custom filename for uploads */
  uploadFileName?: string;
  
  /** Additional parameters for image upload */
  uploadImgParams?: {[key: string]: any};
  
  /** Custom headers for image upload requests */
  uploadImgHeaders?: {[key: string]: string};
  
  /** Send cookies with upload requests */
  withCredentials?: boolean;
  
  /** Upload timeout in milliseconds */
  uploadImgTimeout?: number;
}

Usage Examples:

// Basic server configuration
editor.customConfig.uploadImgServer = '/api/upload/image';

// Advanced server configuration  
editor.customConfig.uploadImgServer = 'https://api.example.com/upload';
editor.customConfig.uploadFileName = 'custom_file_name';
editor.customConfig.uploadImgParams = {
    token: 'user-auth-token',
    folder: 'editor-uploads'
};
editor.customConfig.uploadImgHeaders = {
    'Authorization': 'Bearer ' + authToken,
    'X-Upload-Source': 'wangEditor'
};
editor.customConfig.withCredentials = true;
editor.customConfig.uploadImgTimeout = 30000; // 30 seconds

Upload Limits

Configure upload size and quantity limits.

interface UploadLimits {
  /** Maximum image file size in bytes */
  uploadImgMaxSize?: number;
  
  /** Maximum number of images to upload at once */
  uploadImgMaxLength?: number;
  
  /** Show base64 format for uploaded images */
  uploadImgShowBase64?: boolean;
}

Usage Examples:

// Size and quantity limits
editor.customConfig.uploadImgMaxSize = 5 * 1024 * 1024; // 5MB limit
editor.customConfig.uploadImgMaxLength = 10; // Max 10 images at once

// Base64 image support
editor.customConfig.uploadImgShowBase64 = true; // Allow base64 images

// Strict limits for comments/forums
editor.customConfig.uploadImgMaxSize = 1 * 1024 * 1024; // 1MB
editor.customConfig.uploadImgMaxLength = 3; // Max 3 images

// Generous limits for content creation
editor.customConfig.uploadImgMaxSize = 20 * 1024 * 1024; // 20MB
editor.customConfig.uploadImgMaxLength = 50; // Max 50 images

Upload Hooks

Configure upload lifecycle callbacks.

interface UploadHooks {
  /** Called before upload starts */
  before?: (xhr: XMLHttpRequest, editor: any, files: File[]) => void | false;
  
  /** Called after successful upload */
  success?: (xhr: XMLHttpRequest, editor: any, result: any) => void;
  
  /** Called after failed upload */
  fail?: (xhr: XMLHttpRequest, editor: any, result: any) => void;
  
  /** Called on upload error */
  error?: (xhr: XMLHttpRequest, editor: any, error: any) => void;
  
  /** Called on upload timeout */
  timeout?: (xhr: XMLHttpRequest, editor: any) => void;
  
  /** Custom image insertion function */
  customInsert?: (insertImg: Function, result: any, editor: any) => void;
}

Usage Examples:

editor.customConfig.uploadImgHooks = {
    before: function(xhr, editor, files) {
        console.log('Upload starting...', files.length, 'files');
        
        // Validate files
        for (let file of files) {
            if (!file.type.startsWith('image/')) {
                alert('Only image files are allowed');
                return false; // Cancel upload
            }
        }
        
        // Show loading indicator
        showLoadingIndicator();
    },
    
    success: function(xhr, editor, result) {
        console.log('Upload successful:', result);
        hideLoadingIndicator();
        
        // Process server response
        if (result.code === 0) {
            console.log('Images uploaded:', result.data);
        }
    },
    
    fail: function(xhr, editor, result) {
        console.log('Upload failed:', result);
        hideLoadingIndicator();
        alert('Upload failed: ' + (result.message || 'Unknown error'));
    },
    
    error: function(xhr, editor, error) {
        console.error('Upload error:', error);
        hideLoadingIndicator();
        alert('Upload error occurred');
    },
    
    timeout: function(xhr, editor) {
        console.log('Upload timeout');
        hideLoadingIndicator();
        alert('Upload timed out. Please try again.');
    },
    
    customInsert: function(insertImg, result, editor) {
        // Custom logic for inserting images
        if (result.code === 0 && result.data) {
            result.data.forEach(url => {
                insertImg(url);
            });
        }
    }
};

Custom Upload Implementation

Completely custom upload handling.

interface CustomUpload {
  /** Custom image upload implementation */
  customUploadImg?: (files: FileList, insert: (url: string) => void) => void;
}

Usage Examples:

// Complete custom upload
editor.customConfig.customUploadImg = function(files, insert) {
    console.log('Custom upload:', files.length, 'files');
    
    // Convert to array for easier handling
    const fileArray = Array.from(files);
    
    // Upload each file
    fileArray.forEach(file => {
        const formData = new FormData();
        formData.append('image', file);
        formData.append('timestamp', Date.now().toString());
        
        fetch('/api/custom-upload', {
            method: 'POST',
            body: formData,
            headers: {
                'X-Requested-With': 'XMLHttpRequest'
            }
        })
        .then(response => response.json())
        .then(result => {
            if (result.success) {
                // Insert image into editor
                insert(result.imageUrl);
            } else {
                console.error('Upload failed:', result.error);
                alert('Upload failed: ' + result.error);
            }
        })
        .catch(error => {
            console.error('Upload error:', error);
            alert('Upload error occurred');
        });
    });
};

// AWS S3 upload example
editor.customConfig.customUploadImg = function(files, insert) {
    Array.from(files).forEach(file => {
        // Get presigned URL from your backend
        fetch('/api/s3-presigned-url', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                fileName: file.name,
                fileType: file.type
            })
        })
        .then(response => response.json())
        .then(data => {
            // Upload directly to S3
            return fetch(data.presignedUrl, {
                method: 'PUT',
                body: file,
                headers: {
                    'Content-Type': file.type
                }
            });
        })
        .then(() => {
            // Insert the S3 URL
            const s3Url = `https://your-bucket.s3.amazonaws.com/${file.name}`;
            insert(s3Url);
        })
        .catch(error => {
            console.error('S3 upload error:', error);
            alert('Upload to cloud storage failed');
        });
    });
};

Cloud Storage Integration

Integration with popular cloud storage services.

interface CloudConfig {
  /** Enable Qiniu cloud upload */
  qiniu?: boolean;
}

Usage Examples:

// Qiniu cloud storage
editor.customConfig.qiniu = true;
editor.customConfig.uploadImgServer = 'https://your-qiniu-endpoint.com/upload';

// Custom cloud integration
editor.customConfig.customUploadImg = function(files, insert) {
    // Cloudinary upload example
    const cloudinaryUrl = 'https://api.cloudinary.com/v1_1/your-cloud-name/image/upload';
    
    Array.from(files).forEach(file => {
        const formData = new FormData();
        formData.append('file', file);
        formData.append('upload_preset', 'your-upload-preset');
        
        fetch(cloudinaryUrl, {
            method: 'POST',
            body: formData
        })
        .then(response => response.json())
        .then(result => {
            if (result.secure_url) {
                insert(result.secure_url);
            }
        })
        .catch(error => {
            console.error('Cloudinary upload error:', error);
        });
    });
};

Complete Upload API Interface

interface UploadImgAPI {
  /** Upload image files */
  uploadImg(files: FileList | File[]): void;
}

interface UploadConfig {
  // Server configuration
  uploadImgServer?: string;
  uploadFileName?: string;
  uploadImgParams?: {[key: string]: any};
  uploadImgHeaders?: {[key: string]: string};
  withCredentials?: boolean;
  uploadImgTimeout?: number;
  
  // Upload limits
  uploadImgMaxSize?: number;
  uploadImgMaxLength?: number;
  uploadImgShowBase64?: boolean;
  
  // Upload hooks
  uploadImgHooks?: {
    before?: (xhr: XMLHttpRequest, editor: any, files: File[]) => void | false;
    success?: (xhr: XMLHttpRequest, editor: any, result: any) => void;
    fail?: (xhr: XMLHttpRequest, editor: any, result: any) => void;
    error?: (xhr: XMLHttpRequest, editor: any, error: any) => void;
    timeout?: (xhr: XMLHttpRequest, editor: any) => void;
    customInsert?: (insertImg: Function, result: any, editor: any) => void;
  };
  
  // Cloud storage
  qiniu?: boolean;
  
  // Custom upload
  customUploadImg?: (files: FileList, insert: (url: string) => void) => void;
  
  // UI
  customAlert?: (info: string) => void;
}

Upload Patterns

Progress Tracking

// Upload with progress tracking
editor.customConfig.uploadImgHooks = {
    before: function(xhr, editor, files) {
        // Setup progress tracking
        xhr.upload.onprogress = function(e) {
            if (e.lengthComputable) {
                const percentComplete = (e.loaded / e.total) * 100;
                updateProgressBar(percentComplete);
            }
        };
    },
    
    success: function(xhr, editor, result) {
        hideProgressBar();
    },
    
    error: function(xhr, editor, error) {
        hideProgressBar();
    }
};

Batch Upload Management

// Handle multiple file uploads with coordination
let uploadCounter = 0;
let totalUploads = 0;

editor.customConfig.customUploadImg = function(files, insert) {
    totalUploads = files.length;
    uploadCounter = 0;
    
    showUploadStatus(`Uploading ${totalUploads} images...`);
    
    Array.from(files).forEach((file, index) => {
        uploadSingleFile(file, insert, index);
    });
};

function uploadSingleFile(file, insert, index) {
    const formData = new FormData();
    formData.append('image', file);
    
    fetch('/api/upload', {
        method: 'POST',
        body: formData
    })
    .then(response => response.json())
    .then(result => {
        uploadCounter++;
        updateUploadStatus(`Uploaded ${uploadCounter}/${totalUploads} images`);
        
        if (result.success) {
            insert(result.url);
        }
        
        if (uploadCounter === totalUploads) {
            hideUploadStatus();
        }
    })
    .catch(error => {
        console.error(`Upload ${index + 1} failed:`, error);
        uploadCounter++;
    });
}

Image Optimization

// Client-side image optimization before upload
editor.customConfig.customUploadImg = function(files, insert) {
    Array.from(files).forEach(file => {
        // Optimize image before upload
        optimizeImage(file, {
            maxWidth: 1200,
            maxHeight: 800,
            quality: 0.8
        })
        .then(optimizedFile => {
            return uploadToServer(optimizedFile);
        })
        .then(result => {
            insert(result.url);
        })
        .catch(error => {
            console.error('Image optimization/upload failed:', error);
        });
    });
};

function optimizeImage(file, options) {
    return new Promise((resolve, reject) => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        const img = new Image();
        
        img.onload = function() {
            // Calculate new dimensions
            let { width, height } = img;
            const maxWidth = options.maxWidth || width;
            const maxHeight = options.maxHeight || height;
            
            if (width > maxWidth || height > maxHeight) {
                const ratio = Math.min(maxWidth / width, maxHeight / height);
                width *= ratio;
                height *= ratio;
            }
            
            // Draw and compress
            canvas.width = width;
            canvas.height = height;
            ctx.drawImage(img, 0, 0, width, height);
            
            canvas.toBlob(resolve, file.type, options.quality || 0.9);
        };
        
        img.onerror = reject;
        img.src = URL.createObjectURL(file);
    });
}

Install with Tessl CLI

npx tessl i tessl/npm-wangeditor

docs

commands.md

configuration.md

content-operations.md

editor-management.md

image-upload.md

index.md

menus.md

selection.md

tile.json