235 lines
6.1 KiB
JavaScript
235 lines
6.1 KiB
JavaScript
// Import DOM helpers
|
||
// 导入 DOM 辅助函数
|
||
import {
|
||
$,
|
||
on,
|
||
createElement
|
||
} from './util.dom.js';
|
||
|
||
// Process and compress image file
|
||
// 处理并压缩图片文件
|
||
export async function processImage(file, callback) {
|
||
// Create image element for loading file
|
||
// 创建图片元素用于加载文件
|
||
const img = new Image();
|
||
img.onload = function() {
|
||
const maxW = 1280, // Max width
|
||
maxH = 1280; // 最大宽度/高度
|
||
let w = img.naturalWidth,
|
||
h = img.naturalHeight;
|
||
// Resize if too large
|
||
// 如果图片过大则缩放
|
||
if (w > maxW || h > maxH) {
|
||
const scale = Math.min(maxW / w, maxH / h);
|
||
w = Math.round(w * scale);
|
||
h = Math.round(h * scale)
|
||
}
|
||
// Create canvas for drawing image
|
||
// 创建画布用于绘制图片
|
||
const canvas = createElement('canvas');
|
||
canvas.width = w;
|
||
canvas.height = h;
|
||
const ctx = canvas.getContext('2d');
|
||
ctx.drawImage(img, 0, 0, w, h);
|
||
let dataUrl;
|
||
// Export as webp with 90% quality
|
||
// 导出为 webp,90% 质量
|
||
dataUrl = canvas.toDataURL('image/webp', 0.90);
|
||
callback(dataUrl)
|
||
};
|
||
// Read file as data URL
|
||
// 以 dataURL 方式读取文件
|
||
const reader = new FileReader();
|
||
reader.onload = function(e) {
|
||
img.src = e.target.result
|
||
};
|
||
reader.readAsDataURL(file)
|
||
}
|
||
|
||
// Translate message key
|
||
// 翻译消息 key
|
||
function t(key) {
|
||
const messages = {
|
||
tooLarge: 'Image is too large (over 8MB)', // 图片过大(超过8MB)
|
||
};
|
||
return messages[key] || key
|
||
}
|
||
|
||
// Create image preview element for input
|
||
// 为输入框创建图片预览元素
|
||
function createImagePreview(dataUrl) {
|
||
const preview = createElement('div', {
|
||
class: 'input-image-preview'
|
||
});
|
||
|
||
const img = createElement('img', {
|
||
src: dataUrl,
|
||
class: 'input-image-preview-img'
|
||
});
|
||
|
||
const removeBtn = createElement('button', {
|
||
class: 'input-image-remove-btn',
|
||
type: 'button'
|
||
}, '×');
|
||
|
||
preview.appendChild(img);
|
||
preview.appendChild(removeBtn);
|
||
|
||
return { preview, removeBtn };
|
||
}
|
||
|
||
// Setup image paste functionality
|
||
// 设置图片粘贴功能
|
||
export function setupImagePaste(inputSelector) {
|
||
const input = $(inputSelector);
|
||
if (!input) return;
|
||
|
||
let currentImageDatas = []; // 支持多张图片
|
||
const imagePreviewContainer = createElement('div', { class: 'image-preview-container' });
|
||
input.parentNode.insertBefore(imagePreviewContainer, input);
|
||
|
||
// Function to update placeholder visibility
|
||
function updatePlaceholderVisibility() {
|
||
const placeholder = input.parentNode.querySelector('.input-field-placeholder');
|
||
if (!placeholder) return;
|
||
|
||
const hasText = input.innerText.trim().length > 0;
|
||
const hasImages = currentImageDatas.length > 0;
|
||
|
||
if (hasText || hasImages) {
|
||
placeholder.style.opacity = '0';
|
||
input.classList.remove('is-empty'); // 确保移除 is-empty
|
||
} else {
|
||
placeholder.style.opacity = '1';
|
||
input.classList.add('is-empty'); // 确保添加 is-empty
|
||
}
|
||
}
|
||
|
||
// Initial check for placeholder
|
||
updatePlaceholderVisibility();
|
||
|
||
// Listen to input events to update placeholder
|
||
on(input, 'input', updatePlaceholderVisibility);
|
||
on(input, 'focus', updatePlaceholderVisibility);
|
||
on(input, 'blur', () => {
|
||
// Defer blur check slightly to allow click on remove button
|
||
setTimeout(updatePlaceholderVisibility, 100);
|
||
});
|
||
|
||
on(input, 'paste', function(e) {
|
||
if (!e.clipboardData) return;
|
||
|
||
let imageProcessed = false;
|
||
for (const item of e.clipboardData.items) {
|
||
if (item.type.startsWith('image/')) {
|
||
const file = item.getAsFile();
|
||
if (!file) continue;
|
||
|
||
if (file.size > 8 * 1024 * 1024) {
|
||
alert(t('tooLarge'));
|
||
continue;
|
||
}
|
||
|
||
processImage(file, (dataUrl) => {
|
||
const { preview, removeBtn } = createImagePreview(dataUrl);
|
||
imagePreviewContainer.appendChild(preview);
|
||
currentImageDatas.push({ dataUrl, previewElement: preview });
|
||
|
||
on(removeBtn, 'click', () => {
|
||
preview.remove();
|
||
currentImageDatas = currentImageDatas.filter(img => img.dataUrl !== dataUrl);
|
||
updatePlaceholderVisibility();
|
||
});
|
||
updatePlaceholderVisibility();
|
||
});
|
||
imageProcessed = true;
|
||
}
|
||
}
|
||
if (imageProcessed) {
|
||
e.preventDefault();
|
||
}
|
||
});
|
||
return {
|
||
getCurrentImages: () => currentImageDatas.map(img => img.dataUrl), // 返回所有图片数据
|
||
clearImages: () => {
|
||
imagePreviewContainer.innerHTML = ''; // 清空预览容器
|
||
currentImageDatas = [];
|
||
updatePlaceholderVisibility();
|
||
},
|
||
refreshPlaceholder: updatePlaceholderVisibility // 暴露 placeholder 更新函数
|
||
};
|
||
}
|
||
|
||
// Setup legacy image send functionality (for backward compatibility)
|
||
// 设置旧版图片发送功能(向后兼容)
|
||
export function setupImageSend({
|
||
inputSelector,
|
||
attachBtnSelector,
|
||
fileInputSelector,
|
||
onSend
|
||
}) {
|
||
const input = $(inputSelector);
|
||
const attachBtn = $(attachBtnSelector);
|
||
const fileInput = $(fileInputSelector);
|
||
|
||
if (fileInput) fileInput.setAttribute('accept', 'image/*');
|
||
|
||
if (attachBtn && fileInput) {
|
||
// Click attach triggers file input
|
||
// 点击附件按钮触发文件选择
|
||
on(attachBtn, 'click', () => fileInput.click());
|
||
|
||
// Handle file input change
|
||
// 处理文件选择变化
|
||
on(fileInput, 'change', async function() {
|
||
if (!fileInput.files || !fileInput.files.length) return;
|
||
const file = fileInput.files[0];
|
||
|
||
// Only allow image files
|
||
// 只允许图片文件
|
||
if (!file.type.startsWith('image/')) return;
|
||
|
||
// Check file size
|
||
// 检查文件大小
|
||
if (file.size > 5 * 1024 * 1024) {
|
||
alert(t('tooLarge'));
|
||
return
|
||
}
|
||
|
||
processImage(file, (dataUrl) => {
|
||
if (typeof onSend === 'function') onSend(dataUrl)
|
||
});
|
||
fileInput.value = ''
|
||
})
|
||
}
|
||
|
||
if (input) {
|
||
// Paste image from clipboard
|
||
// 从剪贴板粘贴图片
|
||
on(input, 'paste', function(e) {
|
||
if (!e.clipboardData) return;
|
||
for (const item of e.clipboardData.items) {
|
||
// Only handle image type
|
||
// 只处理图片类型
|
||
if (item.type.startsWith('image/')) {
|
||
const file = item.getAsFile();
|
||
if (!file) continue;
|
||
|
||
// Check file size
|
||
// 检查文件大小
|
||
if (file.size > 5 * 1024 * 1024) {
|
||
alert(t('tooLarge'));
|
||
continue
|
||
}
|
||
|
||
processImage(file, (dataUrl) => {
|
||
if (typeof onSend === 'function') onSend(dataUrl)
|
||
});
|
||
e.preventDefault();
|
||
break
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|