class TranslatorWorkspace extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }); this.render(); this.bindEvents(); // Listen for state changes window.addEventListener('stateChanged', (e) => this.updateUI(e.detail)); window.addEventListener('swapLanguages', () => this.swapTextContent()); } render() { this.shadowRoot.innerHTML = `
Input
0 chars
Translation

Translation will appear here

`; } bindEvents() { const input = this.shadowRoot.getElementById('input-text'); const charCount = this.shadowRoot.getElementById('char-count'); const btnTranslate = this.shadowRoot.getElementById('btn-translate'); const btnClear = this.shadowRoot.getElementById('btn-clear'); const btnPaste = this.shadowRoot.getElementById('btn-paste'); const btnCopy = this.shadowRoot.getElementById('btn-copy'); const btnSwap = this.shadowRoot.getElementById('swap-workspace'); input.addEventListener('input', (e) => { window.appState.inputText = e.target.value; charCount.textContent = `${e.target.value.length} chars`; this.updateTranslateBtn(); }); btnClear.addEventListener('click', () => { input.value = ''; window.appState.inputText = ''; window.appState.outputText = ''; charCount.textContent = '0 chars'; this.updateTranslateBtn(); this.renderOutputEmpty(); }); btnPaste.addEventListener('click', async () => { try { const text = await navigator.clipboard.readText(); input.value = text; window.appState.inputText = text; charCount.textContent = `${text.length} chars`; this.updateTranslateBtn(); window.showToast('Pasted from clipboard', 'success'); } catch (err) { window.showToast('Failed to read clipboard', 'error'); } }); btnCopy.addEventListener('click', () => { if (!window.appState.outputText) return; navigator.clipboard.writeText(window.appState.outputText); window.showToast('Translation copied', 'success'); }); btnTranslate.addEventListener('click', async () => { if (window.appState.isTranslating) return; // Set Loading window.appState.isTranslating = true; btnTranslate.disabled = true; const originalText = btnTranslate.innerHTML; btnTranslate.innerHTML = ` Translating...`; this.renderOutputLoading(); // Call Mock API try { const result = await window.mockApi.translateText({ model: window.appState.model, sourceLang: window.appState.sourceLang, targetLang: window.appState.targetLang, text: window.appState.inputText }); window.appState.outputText = result.translation; this.renderOutputText(result.translation); } catch (error) { window.showToast('Translation failed', 'error'); this.renderOutputEmpty(); } finally { window.appState.isTranslating = false; btnTranslate.disabled = false; btnTranslate.innerHTML = originalText; this.updateTranslateBtn(); } }); btnSwap.addEventListener('click', () => { // Dispatch global swap event (handled by TopBar mostly, but we need to move text if M2M) window.dispatchEvent(new CustomEvent('swapLanguages')); }); } updateTranslateBtn() { const btn = this.shadowRoot.getElementById('btn-translate'); const hasInput = window.appState.inputText.trim().length > 0; const hasFile = window.appState.file !== null; if ((hasInput || hasFile) && !window.appState.isTranslating) { btn.disabled = false; } else { btn.disabled = true; } } updateUI(state) { this.updateTranslateBtn(); } swapTextContent() { // Only swap text content if model allows (M2M). Indictrans has fixed source (En). if(window.appState.model !== 'm2m100-1.2b') return; const input = this.shadowRoot.getElementById('input-text'); if (!input) return; const temp = window.appState.inputText; window.appState.inputText = window.appState.outputText; window.appState.outputText = temp; input.value = window.appState.inputText; this.shadowRoot.getElementById('char-count').textContent = `${window.appState.inputText.length} chars`; if(window.appState.outputText) { this.renderOutputText(window.appState.outputText); } else { this.renderOutputEmpty(); } } renderOutputEmpty() { const wrapper = this.shadowRoot.getElementById('output-wrapper'); wrapper.innerHTML = `

Translation will appear here

`; } renderOutputLoading() { const wrapper = this.shadowRoot.getElementById('output-wrapper'); wrapper.innerHTML = `
`; } renderOutputText(text) { const wrapper = this.shadowRoot.getElementById('output-wrapper'); wrapper.innerHTML = ` `; } } customElements.define('translator-workspace', TranslatorWorkspace);