diff --git a/static/js/smart-canvas.js b/static/js/smart-canvas.js index 8d7f362fb..090c6e590 100644 --- a/static/js/smart-canvas.js +++ b/static/js/smart-canvas.js @@ -11490,11 +11490,16 @@ function renderInputThumbsRow(node){ : smartPreviewImgHtml(img, 256, 'draggable="false"'); const count = (mediaCounters[kind] = (mediaCounters[kind] || 0) + 1); const label = kind === 'audio' ? `音频${count}` : kind === 'video' ? `视频${count}` : `图${count}`; + const referenceMarker = kind === 'image' ? count : 0; + const markerHint = referenceMarker + ? (window.StudioI18n?.lang?.() === 'en' ? `Click to insert @${referenceMarker}` : `单击插入 @${referenceMarker}`) + : ''; const sourceUrl = img.originalLocalUrl || img.url || ''; const key = inputRefKey(img); const removable = manualRefKeys.has(key); const removeBtn = removable ? `` : ''; - return `
${inner}${escapeHtml(label)}${removeBtn}
`; + const tooltip = [img.name || tr('smart.inputNum').replace('{n}', String(i + 1)), title, markerHint].filter(Boolean).join(' · '); + return `
${inner}${escapeHtml(label)}${removeBtn}
`; }).join(''); inputThumbsRow.innerHTML = `
${thumbsHtml}${dedup.length > 1 ? `${escapeHtml(tr('smart.inputCount').replace('{n}', String(dedup.length)))}` : ''}
${addButton}
`; bindSmartPreviewImageFallbacks(inputThumbsRow); @@ -11522,6 +11527,7 @@ function bindInputThumbsDrag(node, items, manualRefKeys=new Set()){ if(!inputThumbsRow) return; let thumbDragIndex = -1; inputThumbsRow.querySelectorAll('.input-thumb').forEach(el => { + let didDrag = false; const index = Number(el.dataset.thumbIndex || -1); const item = items[index]; const key = inputRefKey(item); @@ -11531,10 +11537,15 @@ function bindInputThumbsDrag(node, items, manualRefKeys=new Set()){ el.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); + if(didDrag){ didDrag = false; return; } + if(e.button !== 0 || e.target.closest?.('[data-input-remove-reference]')) return; + const referenceNumber = Number(el.dataset.referenceMarker || 0); + if(referenceNumber > 0) insertInputReferenceMarker(referenceNumber); }); if(!el.draggable) return; el.addEventListener('dragstart', e => { e.stopPropagation(); + didDrag = true; thumbDragIndex = index; el.classList.add('dragging'); e.dataTransfer.effectAllowed = 'move'; @@ -11546,6 +11557,7 @@ function bindInputThumbsDrag(node, items, manualRefKeys=new Set()){ thumbDragIndex = -1; clearInputThumbDropMarkers(); el.classList.remove('dragging'); + setTimeout(() => { didDrag = false; }, 0); }); el.addEventListener('dragover', e => { const manualFromKey = e.dataTransfer.getData('application/x-smart-manual-ref'); @@ -12814,6 +12826,40 @@ function setPromptCaretToEnd(){ sel.addRange(range); mentionRange = range.cloneRange(); } +function promptRangeIsUsable(range){ + const container = range?.commonAncestorContainer; + return Boolean(container && (container === promptInput || promptInput.contains(container))); +} +function insertInputReferenceMarker(referenceNumber){ + const number = Math.floor(Number(referenceNumber)); + if(!promptInput || !Number.isFinite(number) || number < 1 || promptInput.dataset.promptLocked === '1') return false; + const marker = `@${number}`; + const savedPromptRange = promptRangeIsUsable(mentionRange) ? mentionRange.cloneRange() : null; + promptInput.focus(); + const sel = window.getSelection(); + // Clicking a thumbnail may move the live browser selection away from the + // contenteditable before the click handler runs. Prefer the last caret or + // selection captured from the prompt itself. + let range = savedPromptRange + ? savedPromptRange + : (sel?.rangeCount ? sel.getRangeAt(0) : null); + if(!promptRangeIsUsable(range)){ + range = document.createRange(); + range.selectNodeContents(promptInput); + range.collapse(false); + } + range.deleteContents(); + const markerNode = document.createTextNode(marker); + range.insertNode(markerNode); + range.setStartAfter(markerNode); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + mentionRange = range.cloneRange(); + promptInput.dispatchEvent(new Event('input', {bubbles:true})); + promptInput.focus(); + return true; +} function toggleAssetMentionPickerFromThumbs(){ if(!selectedNode()) return; if(mentionInsertMode === 'manual-ref'){ @@ -16680,6 +16726,9 @@ promptInput.addEventListener('input', () => { promptInput.addEventListener('keyup', maybeOpenMentionPicker); promptInput.addEventListener('mouseup', saveMentionRange); promptInput.addEventListener('focus', saveMentionRange); +document.addEventListener('selectionchange', () => { + if(document.activeElement === promptInput) saveMentionRange(); +}); promptInput.addEventListener('keydown', event => { if(event.key === 'Escape') closeMentionPicker(); });