var activeManualSplitCard = null; var MANUAL_SPLIT_MIN_TEXT_HEIGHT = Number(window.MANUAL_SPLIT_TEXT_MIN_HEIGHT_PX) || 96; var MANUAL_SPLIT_MAX_TEXT_HEIGHT = Number(window.MANUAL_SPLIT_TEXT_MAX_HEIGHT_PX) || 420; function getManualSplitRenderKey(card) { var container = card && card.closest ? card.closest('.segments-container') : null; return container && container.dataset ? (container.dataset.renderKey || '') : ''; } function isStaleManualSplitCard(card) { if (!card) return false; var storedKey = card._manualSplitRenderKey || ''; var currentKey = getManualSplitRenderKey(card); return !!storedKey && !!currentKey && storedKey !== currentKey; } function collectManualSplitContent(card) { var textDiv = card.querySelector('.segment-text'); if (!textDiv) { return {words: [], items: []}; } var words = []; var items = []; var wordIdx = -1; Array.from(textDiv.childNodes).forEach(function(node) { if (node.nodeType === Node.ELEMENT_NODE && node.classList && node.classList.contains('word')) { var text = (node.textContent || '').trim(); if (!text) return; wordIdx += 1; words.push({idx: wordIdx, text: text}); items.push({type: 'word', wordIdx: wordIdx, text: text}); return; } var markerText = (node.textContent || '').trim(); if (!markerText || wordIdx < 0) return; items.push({type: 'marker', wordIdx: wordIdx, text: markerText}); }); return {words: words, items: items}; } function resetManualSplitPending(card) { if (!card) return; delete card.dataset.manualSplitPending; delete card.dataset.manualSplitPendingToken; var confirmBtn = card.querySelector('.split-confirm-btn'); if (!confirmBtn) return; confirmBtn.textContent = 'Confirm'; confirmBtn.disabled = !card._manualSplitBoundaryStarts || card._manualSplitBoundaryStarts.size === 0; } function setManualSplitStableLayout(card, textDiv) { if (!card || !textDiv) return; var measured = Math.ceil(textDiv.getBoundingClientRect().height || textDiv.offsetHeight || 0); var minHeight = Math.max(MANUAL_SPLIT_MIN_TEXT_HEIGHT, measured); card.style.setProperty('--manual-split-text-min-height', minHeight + 'px'); card.style.setProperty('--manual-split-text-max-height', MANUAL_SPLIT_MAX_TEXT_HEIGHT + 'px'); } function clearManualSplitStableLayout(card) { if (!card) return; card.style.removeProperty('--manual-split-text-min-height'); card.style.removeProperty('--manual-split-text-max-height'); } function exitManualSplit(card) { if (!card) return; var textDiv = card.querySelector('.segment-text'); if (textDiv && typeof card._manualSplitOriginalHtml === 'string' && !isStaleManualSplitCard(card)) { textDiv.innerHTML = card._manualSplitOriginalHtml; } card.classList.remove('manual-split-mode'); resetManualSplitPending(card); card._manualSplitBoundaryStarts = null; card._manualSplitOriginalHtml = null; card._manualSplitWords = null; card._manualSplitItems = null; card._manualSplitPreviewWordEls = null; card._manualSplitPreviewBreakEls = null; card._manualSplitRenderKey = null; clearManualSplitStableLayout(card); if (activeManualSplitCard === card) activeManualSplitCard = null; } function exitOtherManualSplitModes(exceptCard) { if (activeManualSplitCard && activeManualSplitCard !== exceptCard) { exitManualSplit(activeManualSplitCard); } } function ensureManualSplitPreview(card) { var textDiv = card.querySelector('.segment-text'); var words = card._manualSplitWords || []; var items = card._manualSplitItems || []; if (!textDiv || !words.length) return; if (card._manualSplitPreviewWordEls && card._manualSplitPreviewBreakEls) return; var wrapper = document.createElement('div'); wrapper.className = 'split-preview'; var flow = document.createElement('div'); flow.className = 'split-preview-flow'; var wordEls = new Array(words.length); var breakEls = {}; items.forEach(function(item, itemIdx) { if (itemIdx > 0) { flow.appendChild(document.createTextNode(' ')); } if (item.type === 'word') { if (item.wordIdx > 0) { var br = document.createElement('br'); br.className = 'split-preview-break'; br.dataset.startIndex = String(item.wordIdx); flow.appendChild(br); breakEls[item.wordIdx] = br; } var span = document.createElement('span'); span.className = 'split-preview-word'; span.textContent = item.text; span.dataset.wordIndex = String(item.wordIdx); wordEls[item.wordIdx] = span; flow.appendChild(span); } else { var marker = document.createElement('span'); marker.className = 'split-preview-marker'; marker.textContent = item.text; flow.appendChild(marker); } }); wrapper.appendChild(flow); textDiv.innerHTML = ''; textDiv.appendChild(wrapper); card._manualSplitPreviewWordEls = wordEls; card._manualSplitPreviewBreakEls = breakEls; } function renderManualSplitPreview(card) { var words = card._manualSplitWords || []; var boundaries = card._manualSplitBoundaryStarts || new Set(); if (!words.length) return; ensureManualSplitPreview(card); var wordEls = card._manualSplitPreviewWordEls || []; var breakEls = card._manualSplitPreviewBreakEls || {}; for (var i = 0; i < wordEls.length; i++) { var wordEl = wordEls[i]; if (!wordEl) continue; wordEl.classList.toggle('can-cut', (i > 0 && boundaries.has(i)) || i < words.length - 1); wordEl.classList.toggle('boundary-start', boundaries.has(i)); wordEl.classList.toggle('boundary-end', boundaries.has(i + 1)); } Object.keys(breakEls).forEach(function(startIdx) { var breakEl = breakEls[startIdx]; if (!breakEl) return; breakEl.classList.toggle('active', boundaries.has(Number(startIdx))); }); var confirmBtn = card.querySelector('.split-confirm-btn'); if (confirmBtn) { confirmBtn.disabled = boundaries.size === 0 || card.dataset.manualSplitPending === '1'; } } function enterManualSplit(card) { if (!card) return; exitOtherManualSplitModes(card); var textDiv = card.querySelector('.segment-text'); var content = collectManualSplitContent(card); var words = content.words; if (!textDiv || words.length < 2) return; var audio = card.querySelector('audio'); if (audio) { audio.pause(); stopAnimation(audio, card); } var animBtn = card.querySelector('.animate-btn'); if (animBtn) { animBtn.classList.remove('active'); animBtn.textContent = 'Animate'; } card._manualSplitOriginalHtml = textDiv.innerHTML; card._manualSplitWords = words; card._manualSplitItems = content.items; card._manualSplitRenderKey = getManualSplitRenderKey(card); setManualSplitStableLayout(card, textDiv); card._manualSplitBoundaryStarts = new Set(); card.classList.add('manual-split-mode'); activeManualSplitCard = card; resetManualSplitPending(card); renderManualSplitPreview(card); } function toggleManualSplitBoundary(card, wordIdx) { var words = card._manualSplitWords || []; if (!words.length) return; if (!card._manualSplitBoundaryStarts) { card._manualSplitBoundaryStarts = new Set(); } if (wordIdx > 0 && card._manualSplitBoundaryStarts.has(wordIdx)) { card._manualSplitBoundaryStarts.delete(wordIdx); } else if (wordIdx < words.length - 1 && card._manualSplitBoundaryStarts.has(wordIdx + 1)) { card._manualSplitBoundaryStarts.delete(wordIdx + 1); } else if (wordIdx < words.length - 1) { card._manualSplitBoundaryStarts.add(wordIdx + 1); } renderManualSplitPreview(card); } function submitManualSplit(card) { if (!card || card.dataset.manualSplitPending === '1') return; var boundaries = card._manualSplitBoundaryStarts; if (!boundaries || boundaries.size === 0) return; var cuts = Array.from(boundaries).sort(function(a, b) { return a - b; }).map(function(startIdx) { return startIdx - 1; }); var segIdx = parseInt(card.getAttribute('data-segment-idx'), 10); if (isNaN(segIdx)) return; var confirmBtn = card.querySelector('.split-confirm-btn'); var token = String(Date.now()); card.dataset.manualSplitPending = '1'; card.dataset.manualSplitPendingToken = token; if (confirmBtn) { confirmBtn.disabled = true; confirmBtn.textContent = 'Processing...'; } // Record where to re-anchor the list after the split re-render (keep this // segment stationary instead of jumping). The split's first child keeps this // card's start-time, so the anchor survives the 1->N change. if (window.qaSaveScrollAnchor) window.qaSaveScrollAnchor(card); var payloadStr = JSON.stringify({idx: segIdx, cuts: cuts}); setGradioValue('manual-split-payload', payloadStr); setTimeout(function() { var btn = document.getElementById('manual-split-trigger'); if (btn) btn.click(); }, 50); setTimeout(function() { if (!card.isConnected) return; if (!card.classList.contains('manual-split-mode')) return; if (card.dataset.manualSplitPendingToken !== token) return; resetManualSplitPending(card); }, 8000); } document.addEventListener('click', function(e) { var splitBtn = e.target.closest('.manual-split-btn'); if (splitBtn) { // Greyed for merge members — un-merge first. Inert. if (splitBtn.disabled) return; enterManualSplit(splitBtn.closest('.segment-card')); return; } var cancelBtn = e.target.closest('.split-cancel-btn'); if (cancelBtn) { exitManualSplit(cancelBtn.closest('.segment-card')); return; } var confirmBtn = e.target.closest('.split-confirm-btn'); if (confirmBtn) { submitManualSplit(confirmBtn.closest('.segment-card')); return; } var splitWord = e.target.closest('.split-preview-word'); if (splitWord) { var card = splitWord.closest('.segment-card'); var wordIdx = parseInt(splitWord.dataset.wordIndex, 10); if (!isNaN(wordIdx)) { toggleManualSplitBoundary(card, wordIdx); } } });