document.addEventListener("DOMContentLoaded", async function() {
    const targetElement = document.querySelector(".postform");
    if (!targetElement || !document.querySelector('.tegalogpost')) return;

    // ローディング表示（ログイン確認中）
    const loader = document.createElement("div");
    loader.id = "ex_uploader_loader";
    loader.style.cssText = "color:#999; font-size:0.9em; padding:4px 0;";
    loader.textContent = "読み込み中...";
    targetElement.appendChild(loader);

    // ログイン確認
    try {
        const loggedIn = await fetch('?mode=api&item=ISLOGGEDIN', { cache: 'no-store' }).then(r => r.text());
        if (loggedIn.trim() !== 'YES') {
            loader.remove();
            return;
        }
    } catch (e) {
        loader.remove();
        return;
    }

    // 設定を取得
    let config = { convertToWebpOption: '0', resizeOption: '0', maxDimension: 1000, fileNamingMode: 1 };
    try {
        config = await fetch('upload.php?getConfig=1').then(r => r.json());
    } catch (e) {
        console.error('設定の取得に失敗しました:', e);
    }

    // モード3の場合はユーザーIDを取得
    if (parseInt(config.fileNamingMode) === 3) {
        try {
            config.userId = (await fetch('?mode=api&item=USERID', { cache: 'no-store' }).then(r => r.text())).trim().replace(/[^\w\-]/g, '') || 'user';
        } catch (e) {
            config.userId = 'user';
        }
    }

    loader.remove();

    const uploaderContainer = document.createElement("div");
    uploaderContainer.classList.add("ex_uploader");
    // インラインで非表示にしてからDOMに追加（CSSより確実）
    uploaderContainer.style.display = 'none';
    uploaderContainer.innerHTML = `
    <style>
        #dropArea { text-align: center; border: 2px dashed #ccc; }
        #previewArea img { max-height: 100px; }
        #overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); color: white; display: flex; justify-content: center; align-items: center; z-index: 9; }
        #overlay-content { font-size: 24px; }
        .settings-info { margin-bottom: 10px; color: #666; font-size: 0.7em; }
        /* トリミングモーダル */
        #cropModal { display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); z-index:10; justify-content:center; align-items:center; }
        #cropModal.active { display:flex; }
        #cropModalInner { background:#222; padding:12px; border-radius:8px; max-width:90vw; max-height:90vh; display:flex; flex-direction:column; gap:8px; }
        #cropCanvas { display:block; cursor:crosshair; user-select:none; touch-action:none; }
        #cropActions { display:flex; gap:8px; justify-content:flex-end; }
        #cropActions button { padding:6px 16px; border:none; border-radius:4px; cursor:pointer; font-size:0.95em; }
        #cropConfirm { background:#4caf50; color:#fff; }
        #cropCancel  { background:#888;    color:#fff; }
        #cropInfo    { color:#aaa; font-size:0.85em; text-align:center; }
        .trim-btn { background:rgba(0,120,255,0.8); color:white; border:none; border-radius:50%; cursor:pointer; width:20px; height:20px; font-size:11px; line-height:20px; padding:0; }
    </style>
    <div id="cropModal">
      <div id="cropModalInner">
        <canvas id="cropCanvas"></canvas>
        <div id="cropInfo">ドラッグで範囲を選択 / 内側をドラッグで移動 / 隅をドラッグでリサイズ</div>
        <div id="cropActions">
          <button id="cropCancel">キャンセル</button>
          <button id="cropConfirm">この範囲でトリミング</button>
        </div>
      </div>
    </div>
    <div id="dropArea">ここをクリック(タップ)<br>もしくはD＆D、またはCtrl+Vで画像を選択<br>「投稿する」で画像アップロード<br>加工はアップロード前に選択してください</div>
    <input type="file" id="fileInput" accept=".jpg,.jpeg,.gif,.png,.webp" multiple style="display:none;">
    <div id="previewArea"></div>
    <div>
        <label><input type="checkbox" id="createThumbnail" name="createThumbnail" checked>サムネイルを作成</label>
        <label><input type="checkbox" id="applyThumbnail" name="applyThumbnail">加工をサムネイルに反映</label>
    </div>
    <div>
        <input type="checkbox" id="insertText">テキスト挿入
        <input type="text" id="customText" value="無断転載禁止/DO NOT REPOST">
    </div>
    <div>
        <label><input type="checkbox" id="applyWatermark" name="applyWatermark" value="yes">透かしを入れる</label>
        <select id="watermarkSelect">
            <option value="watermark.png">watermark.png</option>
        </select>
        <div id="watermarkOptions" style="display:none;">
            <label><input type="radio" name="watermarkPosition" value="center" checked>中央</label>
            <label><input type="radio" name="watermarkPosition" value="top-left">左上</label>
            <label><input type="radio" name="watermarkPosition" value="top-right">右上</label>
            <label><input type="radio" name="watermarkPosition" value="bottom-left">左下</label>
            <label><input type="radio" name="watermarkPosition" value="bottom-right">右下</label>
            <label><input type="radio" name="watermarkPosition" value="repeat">全体リピート</label>
        </div>
    </div>
    <div class="settings-info">
        WEBP変換：${config.convertToWebpOption === '1' ? '有効' : '無効'}　サムネイル幅：${config.thumbnailWidth}px　
        リサイズ制限：${config.resizeOption === '1' ? `有効(${config.maxDimension}px)` : '無効'}　
        ファイル名：${{1:'元ファイル名', 2:'ランダム', 3:'日時+ユーザーID'}[config.fileNamingMode] ?? '元ファイル名'}　
        最大枚数：${config.maxFileCount}枚　最大サイズ：${config.maxFileSizeMB}MB
    </div>
    <div id="overlay" style="display:none;"><div id="overlay-content">処理中...</div></div>
    `;

    targetElement.appendChild(uploaderContainer);
    uploaderContainer.style.display = 'block';

    const el = {
        dropArea:       document.getElementById('dropArea'),
        fileInput:      document.getElementById('fileInput'),
        previewArea:    document.getElementById('previewArea'),
        createThumbnail:document.getElementById('createThumbnail'),
        applyThumbnail: document.getElementById('applyThumbnail'),
        insertText:     document.getElementById('insertText'),
        customText:     document.getElementById('customText'),
        applyWatermark: document.getElementById('applyWatermark'),
        watermarkOptions:document.getElementById('watermarkOptions'),
        watermarkSelect:document.getElementById('watermarkSelect'),
        overlay:        document.getElementById('overlay'),
    };

    const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
    let selectedFiles = [];
    let selectedFileNames = new Set();
    let selectedDisplayNames = new Map(); // uploadName -> displayName（[PICT:]タグ表記名）

    const isWebp       = () => config.convertToWebpOption === '1';
    const isClipboard  = (name) => ['image.png','image.jpg','image.jpeg'].includes(name);
    const hasJapanese  = (str) => /[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/.test(str);
    const sanitizeName = (name) => name.replace(/[^\p{L}\p{N}\s\-_\.]/gu, '').replace(/ /g, '_');
    const randomStr    = (n) => Array.from(crypto.getRandomValues(new Uint8Array(n))).map(b => b.toString(36).padStart(2,'0')).join('').slice(0, n);
    const nowStr       = () => { const d = new Date(), p = (n) => String(n).padStart(2,'0'); return `${d.getFullYear()}${p(d.getMonth()+1)}${p(d.getDate())}${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`; };

    // ファイル名モードに応じてベース名を生成（拡張子なし）
    const generateBaseName = (originalName, index) => {
        const mode = parseInt(config.fileNamingMode ?? 1);
        if (mode === 2) return randomStr(12);
        if (mode === 3) return `${nowStr()}${String(index).padStart(2,'0')}_${config.userId ?? 'user'}`;
        // mode 1: 元ファイル名（クリップボード画像はランダム）
        if (isClipboard(originalName)) return `clipboard_${Date.now()}_${randomStr(6)}`;
        return sanitizeName(originalName.replace(/\.[^/.]+$/, ''));
    };

    function handleFiles(files) {
        const rejected = [], duplicates = [], japanese = [];

        Array.from(files).forEach(file => {
            const ext = file.name.split('.').pop().toLowerCase();

            if (hasJapanese(file.name))           { japanese.push(file.name);  return; }
            if (!allowedExtensions.includes(ext)) { rejected.push(file.name);  return; }

            const baseName   = generateBaseName(file.name, Array.from(files).indexOf(file));
            const uploadName = baseName + '.' + ext;           // PHPに渡す名前（元の拡張子）
            const displayName = baseName + '.' + (isWebp() ? 'webp' : ext); // タグに使う表示名

            if (selectedFileNames.has(uploadName)) { duplicates.push(file.name); return; }

            // PHPに送るFileオブジェクトは元の拡張子のままにする（PHP側でWebP変換する）
            const newFile = new File([file], uploadName, { type: file.type });
            selectedFiles.push(newFile);
            selectedFileNames.add(uploadName);
            selectedDisplayNames.set(uploadName, displayName);
            previewImage(file, uploadName, displayName);
            insertTextAtCursor(`[PICT:${displayName}]`);
        });

        if (japanese.length)   alert(`${japanese.join(', ')}は日本語を含むファイル名のため使用できません。\n半角英数字のファイル名に変更してください。`);
        if (rejected.length)   alert(`${rejected.join(', ')}は対応していないファイル形式です。`);
        if (duplicates.length) alert(`${duplicates.join(', ')}は既に選択されています。`);
    }

    function previewImage(file, fileName, displayName) {
        const originalFile = file; // 元画像を保持（再トリミング用）

        const container = document.createElement('div');
        container.style.cssText = 'display:inline-block;position:relative;margin:2px;text-align:center;vertical-align:top;';

        // FileReader(DataURL)の代わりにObjectURLを使用（メモリ効率が良い）
        let previewURL = URL.createObjectURL(file);
        const img = Object.assign(document.createElement('img'), { src: previewURL });
        img.dataset.fileName = fileName;
        img.style.cssText = 'display:block;max-height:100px;';

        const deleteBtn = Object.assign(document.createElement('button'), { textContent: '×' });
        deleteBtn.style.cssText = 'position:absolute;right:0;top:0;background-color:rgba(255,0,0,0.7);color:white;border:none;border-radius:50%;cursor:pointer;width:20px;height:20px;padding:0;';
        deleteBtn.onclick = (e) => {
            e.preventDefault();
            selectedFiles = selectedFiles.filter(f => f.name !== fileName);
            selectedFileNames.delete(fileName);
            selectedDisplayNames.delete(fileName);
            // ObjectURLを解放
            if (previewURL) { URL.revokeObjectURL(previewURL); previewURL = null; }
            img.src = '';
            container.remove();
            removeTagFromTextarea(`[PICT:${displayName}]`);
        };

        const trimBtn = Object.assign(document.createElement('button'), { textContent: 'トリミング' });
        trimBtn.style.cssText = 'display:block;width:100%;margin-top:2px;padding:2px 0;font-size:0.8em;background:rgba(0,120,255,0.8);color:white;border:none;cursor:pointer;border-radius:3px;';
        let lastCrop = null;
        trimBtn.onclick = (e) => {
            e.preventDefault();
            openCropModal(originalFile, fileName, (croppedFile, savedCrop) => {
                lastCrop = savedCrop;
                selectedFiles = selectedFiles.map(f => f.name === fileName ? croppedFile : f);
                // 古いプレビューURLを解放して新しいURLをセット
                if (previewURL) URL.revokeObjectURL(previewURL);
                previewURL = URL.createObjectURL(croppedFile);
                img.src = previewURL;
            }, lastCrop);
        };

        container.append(img, trimBtn, deleteBtn);
        el.previewArea.appendChild(container);
    }

    // ── トリミングモーダル（canvas一枚描画方式）──────────────────────
    function openCropModal(file, fileName, onCrop, lastCrop = null) {
        const modal  = document.getElementById('cropModal');
        const canvas = document.getElementById('cropCanvas');
        const info   = document.getElementById('cropInfo');
        const ctx    = canvas.getContext('2d');

        const HANDLE = 24;
        let imgEl = null, scale = 1;
        let crop = null;
        let state = null;
        let dragHandle = null, startX, startY, startCrop;
        let rafId = null;

        const clamp  = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
        const toOrig = (v) => v / scale;

        function draw() {
            if (!imgEl) return;
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.drawImage(imgEl, 0, 0, canvas.width, canvas.height);
            if (!crop || crop.w < 1 || crop.h < 1) return;

            ctx.fillStyle = 'rgba(0,0,0,0.45)';
            ctx.fillRect(0, 0, canvas.width, crop.y);
            ctx.fillRect(0, crop.y, crop.x, crop.h);
            ctx.fillRect(crop.x + crop.w, crop.y, canvas.width - crop.x - crop.w, crop.h);
            ctx.fillRect(0, crop.y + crop.h, canvas.width, canvas.height - crop.y - crop.h);

            ctx.strokeStyle = '#fff';
            ctx.lineWidth = 2;
            ctx.strokeRect(crop.x, crop.y, crop.w, crop.h);

            const corners = [[crop.x, crop.y], [crop.x + crop.w, crop.y], [crop.x, crop.y + crop.h], [crop.x + crop.w, crop.y + crop.h]];
            ctx.fillStyle = '#fff';
            ctx.strokeStyle = '#555';
            ctx.lineWidth = 1.5;
            corners.forEach(([hx, hy]) => {
                ctx.beginPath();
                ctx.rect(hx - HANDLE/2, hy - HANDLE/2, HANDLE, HANDLE);
                ctx.fill(); ctx.stroke();
            });

            info.textContent = `選択範囲: ${Math.round(toOrig(crop.w))} × ${Math.round(toOrig(crop.h))} px`;
        }

        function hitHandle(px, py) {
            if (!crop) return null;
            for (const [key, hx, hy] of [
                ['nw', crop.x, crop.y], ['ne', crop.x + crop.w, crop.y],
                ['sw', crop.x, crop.y + crop.h], ['se', crop.x + crop.w, crop.y + crop.h],
            ]) {
                if (Math.abs(px - hx) <= HANDLE && Math.abs(py - hy) <= HANDLE) return key;
            }
            return null;
        }

        function hitInside(px, py) {
            return crop && crop.w > 1 && px > crop.x && px < crop.x + crop.w && py > crop.y && py < crop.y + crop.h;
        }

        function pos(e) {
            const r = canvas.getBoundingClientRect();
            const src = e.touches ? e.touches[0] : e;
            return { x: src.clientX - r.left, y: src.clientY - r.top };
        }

        function updateCursor(px, py) {
            const h = hitHandle(px, py);
            canvas.style.cursor = h ? ((h === 'nw' || h === 'se') ? 'nw-resize' : 'ne-resize')
                                 : hitInside(px, py) ? 'move' : 'crosshair';
        }

        function onStart(e) {
            e.preventDefault();
            const p = pos(e), h = hitHandle(p.x, p.y);
            startX = p.x; startY = p.y;
            if (h)                        { state = 'resize'; dragHandle = h; startCrop = { ...crop }; }
            else if (hitInside(p.x, p.y)) { state = 'move';                  startCrop = { ...crop }; }
            else                          { state = 'draw'; crop = { x: p.x, y: p.y, w: 0, h: 0 }; }
        }

        // canvas上のmousemoveでカーソル更新のみ（documentには登録しない）
        function onCanvasMove(e) {
            if (state) return; // ドラッグ中はdocument側のonDragMoveが担当
            const p = pos(e);
            updateCursor(p.x, p.y);
        }

        // ドラッグ中のみdocumentに登録するmove/upハンドラ
        function onDragMove(e) {
            if (!state) return;
            e.preventDefault();
            const p = pos(e), dx = p.x - startX, dy = p.y - startY;
            if (state === 'draw') {
                crop.x = clamp(Math.min(p.x, startX), 0, canvas.width);
                crop.y = clamp(Math.min(p.y, startY), 0, canvas.height);
                crop.w = clamp(Math.abs(p.x - startX), 0, canvas.width  - crop.x);
                crop.h = clamp(Math.abs(p.y - startY), 0, canvas.height - crop.y);
            } else if (state === 'move') {
                crop.x = clamp(startCrop.x + dx, 0, canvas.width  - startCrop.w);
                crop.y = clamp(startCrop.y + dy, 0, canvas.height - startCrop.h);
                crop.w = startCrop.w; crop.h = startCrop.h;
            } else if (state === 'resize') {
                let { x, y, w, h } = startCrop;
                if (dragHandle.includes('e')) w = clamp(w + dx, 10, canvas.width  - x);
                if (dragHandle.includes('s')) h = clamp(h + dy, 10, canvas.height - y);
                if (dragHandle.includes('w')) { const nw = clamp(w - dx, 10, x + w); x += w - nw; w = nw; }
                if (dragHandle.includes('n')) { const nh = clamp(h - dy, 10, y + h); y += h - nh; h = nh; }
                crop = { x, y, w, h };
            }
            if (rafId) cancelAnimationFrame(rafId);
            rafId = requestAnimationFrame(draw);
        }

        function onDragEnd() {
            state = null;
            document.removeEventListener('mousemove', onDragMove);
            document.removeEventListener('touchmove', onDragMove);
            document.removeEventListener('mouseup',   onDragEnd);
            document.removeEventListener('touchend',  onDragEnd);
        }

        // onStart でドラッグ開始時のみ document にリスナーを登録
        const _origOnStart = onStart;
        const onStartWrapped = (e) => {
            _origOnStart(e);
            if (state) {
                document.addEventListener('mousemove', onDragMove);
                document.addEventListener('touchmove', onDragMove, { passive: false });
                document.addEventListener('mouseup',   onDragEnd);
                document.addEventListener('touchend',  onDragEnd);
            }
        };

        canvas.addEventListener('mousedown',  onStartWrapped);
        canvas.addEventListener('touchstart', onStartWrapped, { passive: false });
        canvas.addEventListener('mousemove',  onCanvasMove);

        function cleanup() {
            canvas.removeEventListener('mousedown',  onStartWrapped);
            canvas.removeEventListener('touchstart', onStartWrapped);
            canvas.removeEventListener('mousemove',  onCanvasMove);
            document.removeEventListener('mousemove', onDragMove);
            document.removeEventListener('touchmove', onDragMove);
            document.removeEventListener('mouseup',   onDragEnd);
            document.removeEventListener('touchend',  onDragEnd);
            btnConfirm.removeEventListener('click', onConfirm);
            btnCancel.removeEventListener('click',  onCancel);
            if (rafId) cancelAnimationFrame(rafId);
            // Image解放
            if (imgEl) { imgEl.onload = null; imgEl.onerror = null; imgEl.src = ''; imgEl = null; }
            // canvasをクリア（GPUリソース解放）
            canvas.width = canvas.height = 0;
        }

        const onConfirm = () => {
            if (!crop || crop.w < 2 || crop.h < 2) { info.textContent = '範囲が小さすぎます'; return; }
            const out = document.createElement('canvas');
            out.width  = Math.round(toOrig(crop.w));
            out.height = Math.round(toOrig(crop.h));
            out.getContext('2d').drawImage(imgEl, toOrig(crop.x), toOrig(crop.y), toOrig(crop.w), toOrig(crop.h), 0, 0, out.width, out.height);
            const ext  = fileName.split('.').pop().toLowerCase();
            const mime = ext === 'png' ? 'image/png' : ext === 'webp' ? 'image/webp' : 'image/jpeg';
            const savedCrop = { x: toOrig(crop.x), y: toOrig(crop.y), w: toOrig(crop.w), h: toOrig(crop.h) };
            out.toBlob(blob => {
                out.width = out.height = 0; // GPU解放
                cleanup();
                modal.classList.remove('active');
                onCrop(new File([blob], fileName, { type: mime }), savedCrop);
            }, mime);
        };
        const onCancel = () => { cleanup(); modal.classList.remove('active'); };

        const btnConfirm = document.getElementById('cropConfirm');
        const btnCancel  = document.getElementById('cropCancel');
        btnConfirm.addEventListener('click', onConfirm);
        btnCancel.addEventListener('click',  onCancel);

        const objectURL = URL.createObjectURL(file);
        imgEl = new Image();
        imgEl.onload = () => {
            URL.revokeObjectURL(objectURL);
            const maxW = Math.min(window.innerWidth  * 0.85, 800);
            const maxH = Math.min(window.innerHeight * 0.65, 600);
            scale = Math.min(maxW / imgEl.width, maxH / imgEl.height, 1);
            canvas.width  = Math.round(imgEl.width  * scale);
            canvas.height = Math.round(imgEl.height * scale);
            crop = lastCrop
                ? { x: clamp(lastCrop.x * scale, 0, canvas.width),  y: clamp(lastCrop.y * scale, 0, canvas.height),
                    w: clamp(lastCrop.w * scale, 1, canvas.width),   h: clamp(lastCrop.h * scale, 1, canvas.height) }
                : { x: 0, y: 0, w: canvas.width, h: canvas.height };
            draw();
            modal.classList.add('active');
        };
        imgEl.src = objectURL;
    }

    const tegalogTA = document.querySelector('.tegalogpost');

    function insertTextAtCursor(text) {
        if (!tegalogTA) return;
        const s = tegalogTA.selectionStart, e = tegalogTA.selectionEnd;
        tegalogTA.value = tegalogTA.value.slice(0, s) + text + tegalogTA.value.slice(e);
        tegalogTA.selectionStart = tegalogTA.selectionEnd = s + text.length;
    }

    function removeTagFromTextarea(tag) {
        if (tegalogTA) tegalogTA.value = tegalogTA.value.replace(tag, '');
    }

    // イベントリスナー
    el.createThumbnail.addEventListener('change', () => {
        if (!el.createThumbnail.checked) el.applyThumbnail.checked = false;
    });
    el.applyThumbnail.addEventListener('change', () => {
        if (el.applyThumbnail.checked) el.createThumbnail.checked = true;
    });
    el.applyWatermark.addEventListener('change', () => {
        el.watermarkOptions.style.display = el.applyWatermark.checked ? 'block' : 'none';
        el.watermarkSelect.disabled = !el.applyWatermark.checked;
    });
    document.addEventListener('paste', (e) => {
        const files = Array.from(e.clipboardData.items)
            .filter(i => i.kind === 'file' && i.type.startsWith('image/'))
            .map(i => i.getAsFile());
        if (files.length) handleFiles(files);
    });
    el.dropArea.addEventListener('dragover',  (e) => { e.preventDefault(); el.dropArea.style.borderColor = 'green'; });
    el.dropArea.addEventListener('dragleave', ()  => { el.dropArea.style.borderColor = '#ccc'; });
    el.dropArea.addEventListener('drop',      (e) => { e.preventDefault(); el.dropArea.style.borderColor = '#ccc'; handleFiles(e.dataTransfer.files); });
    el.dropArea.addEventListener('click',     ()  => el.fileInput.click());
    el.fileInput.addEventListener('change',   (e) => handleFiles(e.target.files));

    document.querySelector('form.postform').addEventListener('submit', async function(e) {
        e.preventDefault();
        if (!e.submitter?.classList.contains('postbutton')) return;
        if (selectedFiles.length === 0) { this.submit(); return; }

        el.overlay.style.display = 'flex';
        try {
            const formData = new FormData();
            selectedFiles.forEach(file => {
                formData.append('files[]', file);
                formData.append('fileNames[]', file.name);
                formData.append('displayNames[]', selectedDisplayNames.get(file.name) ?? file.name);
            });
            formData.append('createThumbnail', el.createThumbnail.checked ? 'yes' : 'no');
            formData.append('applyThumbnail',  el.applyThumbnail.checked  ? '1'   : '0');
            if (el.insertText.checked) {
                formData.append('insertText', 'yes');
                formData.append('customText', el.customText.value);
            }
            if (el.applyWatermark.checked) {
                formData.append('applyWatermark',    'yes');
                formData.append('watermarkPosition', document.querySelector('input[name="watermarkPosition"]:checked').value);
                formData.append('watermarkFile',     el.watermarkSelect.value);
            }

            const data = await fetch('upload.php', { method: 'POST', body: formData }).then(r => r.json());
            if (data.error) throw new Error(data.error);

            // サーバー側で実際に保存されたファイル名が異なる場合（衝突時のみ）、本文中のタグを置き換える
            for (const [oldName, newName] of Object.entries(data.renames ?? {})) {
                if (oldName === newName) continue;
                tegalogTA.value = tegalogTA.value.split(`[PICT:${oldName}]`).join(`[PICT:${newName}]`);
            }

            this.submit();
        } catch (err) {
            el.overlay.style.display = 'none';
            alert('画像処理に失敗しました: ' + err.message);
            console.error('Upload error:', err);
        }
    });
});
